mirror of https://github.com/CGAL/cgal
791 lines
13 KiB
C++
791 lines
13 KiB
C++
/******************************************************************
|
|
* Core Library, Version 1.5, August 2002
|
|
* Copyright (c) 1995-2002 Exact Computation Project
|
|
*
|
|
* File: BigRat.inl
|
|
* $Id$
|
|
******************************************************************/
|
|
#ifdef CORE_INLINE
|
|
|
|
/**
|
|
** constructors and destructor; we could leave out some of these
|
|
**/
|
|
|
|
CORE_INLINE bigrational::bigrational()
|
|
{
|
|
num.assign_zero();
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE bigrational::bigrational(int i)
|
|
{
|
|
num = i;
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE bigrational::bigrational(long l)
|
|
{
|
|
num = l;
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE bigrational::bigrational(unsigned long ul)
|
|
{
|
|
num = ul;
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE bigrational::bigrational(const bigint & n)
|
|
{
|
|
num.assign(n);
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE bigrational::bigrational(const bigint & n, const bigint & d)
|
|
{
|
|
if (d.is_zero())
|
|
{
|
|
lidia_error_handler("bigrational", "constructor(n,d)::division by zero.");
|
|
assign_zero();
|
|
}
|
|
else
|
|
{
|
|
num.assign(n);
|
|
den.assign(d);
|
|
this->normalize();
|
|
}
|
|
}
|
|
|
|
CORE_INLINE bigrational::bigrational(const bigrational & a)
|
|
{
|
|
num.assign(a.num);
|
|
den.assign(a.den);
|
|
}
|
|
|
|
CORE_INLINE bigrational::~bigrational()
|
|
{
|
|
}
|
|
|
|
/**
|
|
** CORE_INLINE member functions
|
|
**/
|
|
|
|
CORE_INLINE int bigrational::
|
|
sign() const
|
|
{
|
|
return num.sign();
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_positive() const
|
|
{
|
|
if (num.sign() > 0) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_negative() const
|
|
{
|
|
if (num.sign() < 0) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_zero() const
|
|
{
|
|
if (num.sign() == 0) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_gt_zero() const
|
|
{
|
|
if (num.sign() > 0) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_ge_zero() const
|
|
{
|
|
if (num.sign() >= 0) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_lt_zero() const
|
|
{
|
|
if (num.sign() < 0) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_le_zero() const
|
|
{
|
|
if (num.sign() <= 0) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
is_one() const
|
|
{
|
|
if (num.is_one() && den.is_one()) return true;
|
|
return false;
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
intify(int &i) const
|
|
{
|
|
bigint I;
|
|
divide(I, num, den);
|
|
return I.intify(i);
|
|
}
|
|
|
|
CORE_INLINE bool bigrational::
|
|
longify(long &i) const
|
|
{
|
|
bigint I;
|
|
divide(I, num, den);
|
|
return I.longify(i);
|
|
}
|
|
|
|
CORE_INLINE int bigrational::
|
|
abs_compare(const bigrational & a) const
|
|
{
|
|
bigint r1, r2;
|
|
multiply(r1, num, a.den);
|
|
multiply(r2, den, a.num);
|
|
return r1.abs_compare(r2);
|
|
}
|
|
|
|
CORE_INLINE int bigrational::
|
|
compare(const bigrational & a) const
|
|
{
|
|
bigint r1, r2;
|
|
multiply(r1, num, a.den);
|
|
multiply(r2, den, a.num);
|
|
return r1.compare(r2);
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
normalize()
|
|
{
|
|
int s = den.sign();
|
|
if (s == 0)
|
|
{
|
|
lidia_error_handler("bigrational", "normalize()::division by zero.");
|
|
assign_zero();
|
|
return;
|
|
}
|
|
if (s < 0)
|
|
{
|
|
num.negate();
|
|
den.negate();
|
|
}
|
|
bigint g = bgcd(num, den);
|
|
num /= g;
|
|
den /= g;
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
absolute_value()
|
|
{
|
|
num.absolute_value();
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
negate()
|
|
{
|
|
num.negate();
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
invert()
|
|
{
|
|
if (num.is_zero())
|
|
{
|
|
lidia_error_handler("bigrational", "invert()::division by zero.");
|
|
assign_zero();
|
|
return;
|
|
}
|
|
swap(num, den);
|
|
if (den.is_negative())
|
|
{
|
|
num.negate();
|
|
den.negate();
|
|
}
|
|
}
|
|
|
|
CORE_INLINE bigint bigrational::
|
|
numerator() const
|
|
{
|
|
return num;
|
|
}
|
|
|
|
CORE_INLINE bigint bigrational::
|
|
denominator() const
|
|
{
|
|
return den;
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
multiply_by_denominator()
|
|
{
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
assign_zero()
|
|
{
|
|
num.assign_zero();
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
assign_one()
|
|
{
|
|
num.assign_one();
|
|
den.assign_one();
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
assign(const bigint & n,
|
|
const bigint & d)
|
|
{
|
|
if (d.is_zero())
|
|
{
|
|
lidia_error_handler("bigrational", "assign(n,d)::division by zero.");
|
|
assign_zero();
|
|
return;
|
|
}
|
|
num.assign(n);
|
|
den.assign(d);
|
|
this->normalize();
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
assign(const bigrational & a)
|
|
{
|
|
num.assign(a.num);
|
|
den.assign(a.den);
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
multiply_by_2()
|
|
{
|
|
if (den.is_even())
|
|
den.divide_by_2();
|
|
else
|
|
num.multiply_by_2();
|
|
}
|
|
|
|
CORE_INLINE void bigrational::
|
|
divide_by_2()
|
|
{
|
|
if (num.is_even())
|
|
num.divide_by_2();
|
|
else
|
|
den.multiply_by_2();
|
|
}
|
|
|
|
CORE_INLINE bigint bigrational
|
|
::characteristic () const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
** Type checking
|
|
**/
|
|
|
|
CORE_INLINE bool
|
|
is_bigint(const bigrational & a)
|
|
{
|
|
return a.den.is_one();
|
|
}
|
|
|
|
/**
|
|
** assignments
|
|
**/
|
|
|
|
CORE_INLINE int bigrational::operator = (int i)
|
|
{
|
|
num = i;
|
|
den.assign_one();
|
|
return i;
|
|
}
|
|
|
|
CORE_INLINE long bigrational::operator = (long l)
|
|
{
|
|
num = l;
|
|
den.assign_one();
|
|
return l;
|
|
}
|
|
|
|
CORE_INLINE unsigned long bigrational::operator = (unsigned long ul)
|
|
{
|
|
num = ul;
|
|
den.assign_one();
|
|
return ul;
|
|
}
|
|
|
|
CORE_INLINE bigint bigrational::operator = (const bigint & a)
|
|
{
|
|
num.assign(a);
|
|
den.assign_one();
|
|
return a;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator = (const bigrational & a)
|
|
{
|
|
if (this == &a) // Bug fixed: avoid self-assignment
|
|
return *this; // Zilin Du, 07/11/01
|
|
num.assign(a.num);
|
|
den.assign(a.den);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
** comparisons
|
|
**/
|
|
|
|
CORE_INLINE bool operator == (const bigrational & a, const bigrational & b)
|
|
{ if (a.compare(b) == 0) return true;
|
|
return false; }
|
|
|
|
CORE_INLINE bool operator != (const bigrational & a, const bigrational & b)
|
|
{ if (a.compare(b) != 0) return true;
|
|
return false; }
|
|
|
|
CORE_INLINE bool operator > (const bigrational & a, const bigrational & b)
|
|
{ if (a.compare(b) > 0) return true;
|
|
return false; }
|
|
|
|
CORE_INLINE bool operator >= (const bigrational & a, const bigrational & b)
|
|
{ if (a.compare(b) >= 0) return true;
|
|
return false; }
|
|
|
|
CORE_INLINE bool operator < (const bigrational & a, const bigrational & b)
|
|
{ if (a.compare(b) < 0) return true;
|
|
return false; }
|
|
|
|
CORE_INLINE bool operator <= (const bigrational & a, const bigrational & b)
|
|
{ if (a.compare(b) <= 0) return true;
|
|
return false; }
|
|
|
|
/**
|
|
** operator overloading
|
|
**/
|
|
|
|
CORE_INLINE bigrational operator - (const bigrational & a)
|
|
{
|
|
bigrational c(a);
|
|
c.num.negate();
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational operator + (const bigrational & a, const bigrational & b)
|
|
{
|
|
bigrational c;
|
|
add(c, a, b);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational operator - (const bigrational & a, const bigrational & b)
|
|
{
|
|
bigrational c;
|
|
subtract(c, a, b);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational operator * (const bigrational & a, const bigrational & b)
|
|
{
|
|
bigrational c;
|
|
multiply(c, a, b);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational operator / (const bigrational & a, const bigrational & b)
|
|
{
|
|
bigrational c;
|
|
divide(c, a, b);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational operator << (const bigrational & a, unsigned long ui)
|
|
{
|
|
bigrational c;
|
|
shift_left(c, a, ui);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational operator >> (const bigrational & a, unsigned long ui)
|
|
{
|
|
bigrational c;
|
|
shift_right(c, a, ui);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator += (const bigrational & a)
|
|
{
|
|
add(*this, *this, a);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator -= (const bigrational & a)
|
|
{
|
|
subtract(*this, *this, a);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator *= (const bigrational & a)
|
|
{
|
|
multiply(*this, *this, a);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator /= (const bigrational & a)
|
|
{
|
|
divide(*this, *this, a);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator <<= (unsigned long ui)
|
|
{
|
|
shift_left(*this, *this, ui);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator >>= (unsigned long ui)
|
|
{
|
|
shift_right(*this, *this, ui);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator++ ()
|
|
{
|
|
add(num, num, den);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE bigrational & bigrational::operator-- ()
|
|
{
|
|
subtract(num, num, den);
|
|
return *this;
|
|
}
|
|
|
|
CORE_INLINE int bigrational::operator ! ()
|
|
{
|
|
return num.is_zero();
|
|
}
|
|
|
|
/**
|
|
** Procedural versions
|
|
**/
|
|
|
|
CORE_INLINE void
|
|
invert(bigrational & a, const bigrational & b)
|
|
{
|
|
a.assign(b);
|
|
a.invert();
|
|
}
|
|
|
|
CORE_INLINE void
|
|
lidia_negate(bigrational & a, const bigrational & b)
|
|
{
|
|
a.assign(b);
|
|
a.negate();
|
|
}
|
|
|
|
CORE_INLINE void multiply_by_two(bigrational & c, const bigrational & a)
|
|
{
|
|
c.assign(a);
|
|
c.multiply_by_2();
|
|
}
|
|
|
|
CORE_INLINE void divide_by_two(bigrational & c, const bigrational & a)
|
|
{
|
|
c.assign(a);
|
|
c.divide_by_2();
|
|
}
|
|
|
|
CORE_INLINE void
|
|
shift_left(bigrational & c, const bigrational & a, long ui)
|
|
{
|
|
if (ui < 0)
|
|
{
|
|
lidia_error_handler("bigrational", "shift_left()::index is negative.");
|
|
c.num.assign(a.num);
|
|
c.den.assign(a.den);
|
|
return;
|
|
}
|
|
c.den.assign(a.den);
|
|
shift_left(c.num, a.num, ui);
|
|
c.normalize();
|
|
}
|
|
|
|
CORE_INLINE void
|
|
shift_right(bigrational & c, const bigrational & a, long ui)
|
|
{
|
|
if (ui < 0)
|
|
{
|
|
lidia_error_handler("bigrational", "shift_right()::index is negative.");
|
|
c.num.assign(a.num);
|
|
c.den.assign(a.den);
|
|
return;
|
|
}
|
|
c.num.assign(a.num);
|
|
shift_left(c.den, a.den, ui);
|
|
c.normalize();
|
|
}
|
|
|
|
CORE_INLINE void
|
|
inc(bigrational & c)
|
|
{
|
|
add(c.num, c.num, c.den);
|
|
}
|
|
|
|
CORE_INLINE void
|
|
dec(bigrational & c)
|
|
{
|
|
subtract(c.num, c.num, c.den);
|
|
}
|
|
|
|
CORE_INLINE void
|
|
add(bigrational & c, const bigrational & a, long i)
|
|
{
|
|
bigint tmp;
|
|
multiply(tmp, a.den, i);
|
|
add(c.num, a.num, tmp);
|
|
c.den.assign(a.den);
|
|
}
|
|
|
|
CORE_INLINE void
|
|
add(bigrational & c, long i, const bigrational & a)
|
|
{
|
|
bigint tmp;
|
|
multiply(tmp, a.den, i);
|
|
add(c.num, a.num, tmp);
|
|
c.den.assign(a.den);
|
|
}
|
|
|
|
CORE_INLINE void
|
|
subtract(bigrational & c, const bigrational & a, long i)
|
|
{
|
|
bigint tmp;
|
|
multiply(tmp, a.den, i);
|
|
subtract(c.num, a.num, tmp);
|
|
c.den.assign(a.den);
|
|
}
|
|
|
|
CORE_INLINE void
|
|
subtract(bigrational & c, long i, const bigrational & a)
|
|
{
|
|
bigint tmp;
|
|
multiply(tmp, a.den, i);
|
|
subtract(c.num, a.num, tmp);
|
|
c.num.negate();
|
|
c.den.assign(a.den);
|
|
}
|
|
|
|
CORE_INLINE void
|
|
multiply(bigrational & c, const bigrational & a, long i)
|
|
{
|
|
multiply(c.num, a.num, i);
|
|
c.den.assign(a.den);
|
|
c.normalize();
|
|
}
|
|
|
|
CORE_INLINE void
|
|
multiply(bigrational & c, long i, const bigrational & a)
|
|
{
|
|
multiply(c.num, a.num, i);
|
|
c.den.assign(a.den);
|
|
c.normalize();
|
|
}
|
|
|
|
CORE_INLINE void
|
|
divide(bigrational & c, const bigrational & a, long i)
|
|
{
|
|
c.num.assign(a.num);
|
|
multiply(c.den, a.den, i);
|
|
c.normalize();
|
|
}
|
|
|
|
CORE_INLINE void
|
|
divide(bigrational & c, long i, const bigrational & a)
|
|
{
|
|
if (&c == &a)
|
|
{
|
|
c.invert();
|
|
multiply(c.num, c.num, i);
|
|
}
|
|
else
|
|
{
|
|
multiply(c.num, a.den, i);
|
|
c.den.assign(a.num);
|
|
}
|
|
c.normalize();
|
|
}
|
|
|
|
/**
|
|
** functions
|
|
**/
|
|
|
|
CORE_INLINE bigrational
|
|
abs(const bigrational & a)
|
|
{
|
|
bigrational c(a);
|
|
c.absolute_value();
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigrational
|
|
inverse(const bigrational & a)
|
|
{
|
|
bigrational c(a);
|
|
c.invert();
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigint
|
|
numerator(const bigrational & a)
|
|
{
|
|
bigint c(a.num);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigint
|
|
denominator(const bigrational & a)
|
|
{
|
|
bigint c(a.den);
|
|
return c;
|
|
}
|
|
|
|
CORE_INLINE bigint
|
|
round(const bigrational & a)
|
|
{
|
|
bigrational c;
|
|
bigint rn(a.num), rd(a.den);
|
|
rn.multiply_by_2();
|
|
add(rn, rn, rd);
|
|
rd.multiply_by_2();
|
|
c.num.assign(rn);
|
|
c.den.assign(rd);
|
|
return floor(c);
|
|
}
|
|
|
|
CORE_INLINE bigint
|
|
floor(const bigrational & a)
|
|
{
|
|
bigint q, r;
|
|
div_rem(q, r, abs(a.num), abs(a.den));
|
|
if (a.sign() < 0 && r.sign() != 0)
|
|
{
|
|
if (a.sign() < 0)
|
|
q.negate();
|
|
dec(q);
|
|
}
|
|
else
|
|
{
|
|
if (a.sign() < 0)
|
|
q.negate();
|
|
}
|
|
return q;
|
|
}
|
|
|
|
CORE_INLINE bigint
|
|
ceiling(const bigrational & a)
|
|
{
|
|
bigint q, r;
|
|
div_rem(q, r, abs(a.num), abs(a.den));
|
|
if (a.sign() >= 0 && r.sign() != 0)
|
|
inc(q);
|
|
if (a.sign() < 0)
|
|
q.negate();
|
|
return q;
|
|
}
|
|
|
|
CORE_INLINE bigint
|
|
truncate(const bigrational & a)
|
|
{
|
|
bigint q, r;
|
|
div_rem(q, r, abs(a.num), abs(a.den));
|
|
if (a.sign() < 0)
|
|
q.negate();
|
|
return q;
|
|
}
|
|
|
|
CORE_INLINE double
|
|
dbl(const bigrational & a)
|
|
{
|
|
if (a.num.is_zero())
|
|
return 0.0;
|
|
|
|
long ln = a.num.bit_length();
|
|
long ld = a.den.bit_length();
|
|
long en = 0, ed = 0;
|
|
|
|
if (ln > 1023)
|
|
en = ln - 1023;
|
|
if (ld > 1023)
|
|
ed = ld - 1023;
|
|
|
|
bigint an = a.num >> en;
|
|
bigint ad = a.den >> ed;
|
|
|
|
// an = (a/2^en)*2^en
|
|
// ad = (a/2^ed)*2^ed
|
|
|
|
double d = dbl(an) / dbl(ad);
|
|
d = ldexp(d, (int)(en - ed));
|
|
|
|
return d;
|
|
}
|
|
|
|
CORE_INLINE void
|
|
square(bigrational & a, const bigrational & b)
|
|
{
|
|
square(a.num, b.num);
|
|
square(a.den, b.den);
|
|
}
|
|
|
|
CORE_INLINE void
|
|
swap(bigrational & a, bigrational & b)
|
|
{
|
|
swap(a.num, b.num);
|
|
swap(a.den, b.den);
|
|
}
|
|
|
|
CORE_INLINE std::ostream & operator << (std::ostream & out, const bigrational & a)
|
|
{
|
|
bigint n = a.num;
|
|
bigint d = a.den;
|
|
|
|
if (n.is_zero() || d.is_one())
|
|
out << n;
|
|
else
|
|
out << n << "/" << d;
|
|
return out;
|
|
}
|
|
|
|
CORE_INLINE int
|
|
string_to_bigrational(char *s, char *t, bigrational & a)
|
|
{
|
|
long i = string_to_bigint(s, a.num);
|
|
long j = string_to_bigint(t, a.den);
|
|
a.normalize();
|
|
return (i + j);
|
|
}
|
|
|
|
CORE_INLINE int
|
|
bigrational_to_string(const bigrational & a, char *s, char *t)
|
|
{
|
|
int i = bigint_to_string(a.num, s);
|
|
int j = bigint_to_string(a.den, t);
|
|
return (i + j);
|
|
}
|
|
|
|
#endif
|
|
|