cgal/Packages/Core/include/BigFloat.inl

549 lines
12 KiB
C++

/******************************************************************
* Core Library, Version 1.5, August 2002
* Copyright (c) 1995-2002 Exact Computation Project
*
* File: BigFloat.inl
* $Id$
******************************************************************/
#ifdef CORE_INLINE
// class BigFloatRep
// static member
CORE_INLINE void BigFloatRep::error(const char* msg)
{
// output error message to stderr
std::cerr << "BigFloat Error : " << msg << std::endl;
abort();
exit(1);
}
CORE_INLINE long BigFloatRep::chunkCeil(long bits) {
if (bits > 0)
return (bits - 1) / CHUNK_BIT + 1;
else
return - (- bits) / CHUNK_BIT;
}//chunkCeil
CORE_INLINE long BigFloatRep::chunkFloor(long bits) {
if (bits >= 0)
return bits / CHUNK_BIT;
else
return - (- bits - 1) / CHUNK_BIT - 1;
}//chunkFloor
// bits(c) returns the number of bits in c chunks:
CORE_INLINE long BigFloatRep::bits(long chunks) {
return CHUNK_BIT * chunks;
}//bits
CORE_INLINE BigInt BigFloatRep::chunkShift(const BigInt& x, long s) {
if (!s || sign(x) == 0)
return x;
else if (s > 0)
// shift left
if (sign(x) > 0)
return x << bits(s);
else // x < 0
return - ((-x) << bits(s));
else // shift right
if (sign(x) > 0)
return x >> bits(-s);
else // x < 0
return - ((-x) >> bits(-s));
}//chunkShift
CORE_INLINE BigFloatRep* BigFloatRep::exp2(int e) {
long ee; // this is going to be the exponent
if (e >= 0)
ee = e/CHUNK_BIT;
else
ee = - ((-e + CHUNK_BIT -1)/CHUNK_BIT);
int rem = e - (ee * CHUNK_BIT); // Assert: 0 <= rem < CHUNK_BIT
return new BigFloatRep((1<<rem), 0, ee); // assume CHUNK_BIT is less than int wid
}
// constructor
CORE_INLINE BigFloatRep::BigFloatRep(const BigInt& I, unsigned long u, long l)
: m(I), err(u), exp(l), refCount(0)
{}
CORE_INLINE BigFloatRep::BigFloatRep(const char *str)
: m(0), err(0), exp(0), refCount(0)
{
fromString(str);
}
CORE_INLINE BigRat BigFloatRep::BigRatize() const {
if (exp >= 0)
return BigRat(chunkShift(m, exp), 1);
else
return BigRat(m, chunkShift(1, - exp));
}
// the destructor
CORE_INLINE BigFloatRep::~BigFloatRep()
{}
CORE_INLINE void BigFloatRep::approx(const BigRat& R, const extLong& r, const extLong& a) {
div(R.numerator(), R.denominator(), r, a);
}
// eliminate trailing zeroes
CORE_INLINE void BigFloatRep::eliminateTrailingZeroes() {
// eliminate trailing 0's -- IP 10/9/98
if (err == 0 && m != 0) {
while ((m & ((1 << CHUNK_BIT) - 1)) == 0) {
m >>= CHUNK_BIT;
exp++;
}
}
}
// bultin functions
CORE_INLINE extLong BigFloatRep::lMSB() const {
if (!isZeroIn())
return extLong(floorLg(abs(m) - err)) + bits(exp);
else
return extLong(CORE_negInfty);
}
CORE_INLINE extLong BigFloatRep::uMSB() const {
return extLong(floorLg(abs(m) + err)) + bits(exp);
}
CORE_INLINE extLong BigFloatRep::MSB() const {
// Note : MSB is undefined if it's not exact.
if (sign(m)) // sign(m) is non-zero
return extLong(floorLg(m)) + bits(exp);
else
return extLong(CORE_negInfty);
}
CORE_INLINE extLong BigFloatRep::flrLgErr() const {
if (err)
return extLong(flrLg(err)) + bits(exp);
else
return extLong(CORE_negInfty);
}
CORE_INLINE extLong BigFloatRep::clLgErr() const {
if (err)
return extLong(clLg(err)) + bits(exp);
else
return extLong(CORE_negInfty);
}
// isZero() = true iff zero is inside the interval of BigFloat:
CORE_INLINE bool BigFloatRep::isZeroIn() const {
if (err == 0) return (m == 0); //Nov 6, 2002: bug fix!
long lm = m.bit_length();
if (lm > CHUNK_BIT+2)
return false; // since err < 4 * 2^{CHUNK_BIT}
else
return (abs(m) <= BigInt(err));
}
CORE_INLINE int BigFloatRep::signM() const {
return sign(m);
}
CORE_INLINE double BigFloatRep::lg10(BigInt x) {
if (x == 0)
return 0;
BigInt t(abs(x));
long l = -1;
double d = 0;
while (t > 0) {
l++;
d /= 10;
d += bigIntToLong(t%10);
t /= 10;
}
return log10(d) + l;
}
// this is a simpler form of lg10()
CORE_INLINE long BigFloatRep::floorlg10(BigInt x)
{
if (x == 0)
return 0;
BigInt t(abs(x));
long l = -1;
while (t > 0) {
l++;
t /= 10;
}
return l;
}
CORE_INLINE std::ostream& BigFloatRep::operator<<(std::ostream& o) const {
bool sci = (o.flags() & std::ios ::scientific);
BigFloatRep::DecimalOutput r = toDecimal(o.precision(), sci);
if (r.sign == -1)
o << "-";
o << r.rep;
return o;
}
CORE_INLINE void BigFloatRep::dump() const {
std::cout << "---- BFRep: " << this << " ----" << std::endl;
std::cout << " BF value: ";
this->operator<<(std::cout);
std::cout << std::endl;
std::cout << " m = " << m << std::endl;
std::cout << " err = " << err << std::endl;
std::cout << " exp = " << exp << std::endl;
std::cout << " -- End of BFRep " << this << " -- " << std::endl;
}
// class BigFloat
// constructors
CORE_INLINE BigFloat::BigFloat(BigFloatRep * r) { //private
this->rep = r;
rep->refCount ++;
}
CORE_INLINE BigFloat::BigFloat() {
rep = new BigFloatRep(CORE_BIGINT_ZERO, 0, 0);
rep->refCount++;
}
CORE_INLINE BigFloat::BigFloat(int i) {
rep = new BigFloatRep(i);
rep->refCount++;
}
CORE_INLINE BigFloat::BigFloat(long l) {
rep = new BigFloatRep(l);
rep->refCount++;
}
CORE_INLINE BigFloat::BigFloat(double d) {
rep = new BigFloatRep(d);
rep->refCount++;
}
CORE_INLINE BigFloat::BigFloat(const BigInt& I, unsigned long u, long l) {
// default values: u=0, l=0
rep = new BigFloatRep(I, u, l);
rep->refCount++;
}
CORE_INLINE BigFloat::BigFloat(const char *str) {
rep = new BigFloatRep(str);
rep->refCount++;
}
CORE_INLINE BigFloat::BigFloat(const BigFloat& x) {
rep = x.rep;
rep->refCount++;
}
CORE_INLINE BigFloat::BigFloat(const BigRat& R, const extLong& r, const extLong& a) {
// default values: r= defRelPrec, a= defAbsPrec
rep = new BigFloatRep();
rep->refCount++;
rep->approx(R, r, a);
}
CORE_INLINE BigRat BigFloat::BigRatize() const {
return rep->BigRatize();
}
// the destructor
CORE_INLINE BigFloat::~BigFloat() {
if (--rep->refCount == 0)
delete rep;
}
// assignment operator
CORE_INLINE BigFloat& BigFloat::operator= (const BigFloat& x) {
if (this == &x) //Bug fixed: avoid self-assignment
return *this; //Zilin Du, 07/11/01
if (--rep->refCount == 0)
delete rep;
rep = x.rep;
rep->refCount++;
return *this;
}
// approximation
CORE_INLINE void BigFloat::approx(const BigInt& I, const extLong& r, const extLong& a) {
if ((rep->refCount) > 1) {// *rep is shared
--rep->refCount;
rep = new BigFloatRep();
rep->refCount++;
}
rep->trunc(I, r, a);
}
CORE_INLINE void BigFloat::approx(const BigFloat& B, const extLong& r, const extLong& a) {
if ((rep->refCount) > 1) {// *rep is shared
--rep->refCount;
rep = new BigFloatRep();
rep->refCount++;
}
rep->approx(*B.rep, r, a);
}
CORE_INLINE void BigFloat::approx(const BigRat& R, const extLong& r, const extLong& a) {
if (rep->refCount > 1) {// *rep is shared
--rep->refCount;
rep = new BigFloatRep();
rep->refCount++;
}
rep->approx(R, r, a);
}
// unary minus
CORE_INLINE BigFloat BigFloat::operator- () const {
return BigFloat(- rep->m, rep->err, rep->exp);
}
// arithmetics
CORE_INLINE BigFloat operator+ (const BigFloat& x, const BigFloat& y) {
BigFloat z;
z.rep->add(*x.rep, *y.rep);
return z;
}
CORE_INLINE BigFloat operator- (const BigFloat& x, const BigFloat& y) {
BigFloat z;
z.rep->sub(*x.rep, *y.rep);
return z;
}
CORE_INLINE BigFloat operator* (const BigFloat& x, const BigFloat& y) {
BigFloat z;
z.rep->mul(*x.rep, *y.rep);
return z;
}
CORE_INLINE BigFloat operator/ (const BigFloat& x, const BigFloat& y) {
BigFloat z;
z.rep->div(*x.rep, *y.rep, defBFdivRelPrec);
return z;
}
CORE_INLINE BigFloat BigFloat::div(const BigFloat& x, const extLong& r) const {
BigFloat y;
y.rep->div(*rep, *x.rep, r);
return y;
}
// squareroot
CORE_INLINE BigFloat BigFloat::sqrt(const extLong& a) const {
BigFloat x;
x.rep->sqrt(*rep, a);
#ifdef DEBUG
assert((x * x - (*this)).abs() < BigFloat(ldexp(2.0, -a.asLong())));
#endif
return x;
}
// squareroot with initial approximation A
CORE_INLINE BigFloat BigFloat :: sqrt(const extLong& a, const BigFloat& A) const
{
BigFloat x;
x.rep->sqrt(*rep, a, A);
#ifdef DEBUG
assert((x * x - (*this)).abs() < BigFloat(ldexp(2.0, -a.asLong())));
#endif
return x;
}
// sqrt to defAbsPrec:
CORE_INLINE BigFloat sqrt(const BigFloat& x) {
return x.sqrt(defBFsqrtAbsPrec);
}
// comparisons
CORE_INLINE int BigFloat::compare(const BigFloat& x) const {
return rep->compareMExp(*x.rep);
}
CORE_INLINE bool operator== (const BigFloat& x, const BigFloat& y) {
return x.compare(y) == 0;
}
CORE_INLINE bool operator!= (const BigFloat& x, const BigFloat& y) {
return x.compare(y) != 0;
}
CORE_INLINE bool operator< (const BigFloat& x, const BigFloat& y) {
return x.compare(y) < 0;
}
CORE_INLINE bool operator<= (const BigFloat& x, const BigFloat& y) {
return x.compare(y) <= 0;
}
CORE_INLINE bool operator> (const BigFloat& x, const BigFloat& y) {
return x.compare(y) > 0;
}
CORE_INLINE bool operator>= (const BigFloat& x, const BigFloat& y) {
return x.compare(y) >= 0;
}
// arithmetic and assignment opeartors
CORE_INLINE BigFloat& BigFloat::operator+= (const BigFloat& x) {
BigFloat z;
z.rep->add(*rep, *x.rep);
if (--rep->refCount == 0)
delete rep;
rep = z.rep;
rep->refCount++;
return *this;
}
CORE_INLINE BigFloat& BigFloat::operator-= (const BigFloat& x) {
BigFloat z;
z.rep->sub(*rep, *x.rep);
if (--rep->refCount == 0)
delete rep;
rep = z.rep;
rep->refCount++;
return *this;
}
CORE_INLINE BigFloat& BigFloat::operator*= (const BigFloat& x) {
BigFloat z;
z.rep->mul(*rep, *x.rep);
if (--rep->refCount == 0)
delete rep;
rep = z.rep;
rep->refCount++;
return *this;
}
CORE_INLINE BigFloat& BigFloat::operator/= (const BigFloat& x) {
BigFloat z;
z.rep->div(*rep, *x.rep, defBFdivRelPrec);
if (--rep->refCount == 0)
delete rep;
rep = z.rep;
rep->refCount++;
return *this;
}
// cast operators
CORE_INLINE double BigFloat::toDouble() const {
return rep->toDouble();
}
CORE_INLINE float BigFloat::toFloat() const {
return (float)rep->toDouble();
}
CORE_INLINE BigInt BigFloat::toBigInt() const {
return rep->toBigInt();
}
CORE_INLINE long BigFloat::toLong() const {
long l = rep->toLong();
if ((l == LONG_MAX) || (l == LONG_MIN))
return l; // return the overflown value.
if ((sign() < 0) && (*this != BigFloat(l))) {
// a negative value not exactly rounded.
l--; // rounded to floor.
}
return l;
}
CORE_INLINE int BigFloat::toInt() const {
return (int)rep->toLong();
}
// builtin function
CORE_INLINE bool BigFloat::isExact() const {
return rep->err == 0;
}
CORE_INLINE extLong BigFloat::lMSB() const {
return rep->lMSB();
}
CORE_INLINE extLong BigFloat::uMSB() const {
return rep->uMSB();
}
CORE_INLINE extLong BigFloat::MSB() const {
return rep->MSB();
}
CORE_INLINE extLong BigFloat::flrLgErr() const {
return rep->flrLgErr();
}
CORE_INLINE extLong BigFloat::clLgErr() const {
return rep->clLgErr();
}
CORE_INLINE bool BigFloat::isZeroIn() const {
return rep->isZeroIn();
}
CORE_INLINE int BigFloat::sign() const {
return rep->signM();
}
CORE_INLINE int sign(const BigFloat& x) {
return x.sign();
}
CORE_INLINE BigFloat BigFloat::abs() const {
if (rep->signM() >= 0)
return BigFloat(*this);
else
return BigFloat(- rep->m, rep->err, rep->exp);
}
CORE_INLINE BigFloat abs(const BigFloat& x) {
return x.abs();
}
// stream operators
CORE_INLINE std::ostream& operator<< (std::ostream& o, const BigFloat& x) {
x.rep->operator<<(o);
return o;
}
CORE_INLINE std::istream& operator>> (std::istream& i, BigFloat& x) {
x.rep->operator>>(i);
return i;
}
CORE_INLINE void BigFloat::dump() const {
rep->dump();
}
#endif