/****************************************************************** * Core Library Version 1.6, June 2003 * Copyright (c) 1995-2002 Exact Computation Project * * File: Expr.h * * Written by * Koji Ouchi * Chee Yap * Igor Pechtchanski * Vijay Karamcheti * Chen Li * Zilin Du * Sylvain Pion * Vikram Sharma * WWW URL: http://cs.nyu.edu/exact/ * Email: exact@cs.nyu.edu * * $Id$ *****************************************************************/ #ifndef CORE_EXPR_H #define CORE_EXPR_H #include CORE_BEGIN_NAMESPACE /// \class Expr Expr.h /// \brief Expr is a class of Expression in Level 3 class Expr { public: ExprRep* rep; ///< handle to the "real" representation /// \name Constructors and Destructor //@{ /// default constructor Expr() { rep = new ConstDoubleRep(); } /// copy constructor Expr(const Expr& e) { rep = e.rep; rep->incRefCount(); } /// constructor for int Expr(int i) { rep = new ConstDoubleRep(i); } /// constructor for unsigned int Expr(unsigned int ui) { rep = new ConstDoubleRep(ui); } /// constructor for long Expr(long l) { rep = new ConstRealRep(Real(l)); } /// constructor for unsigned long Expr(unsigned long ul) { rep = new ConstRealRep(Real(ul)); } /// constructor for float /** \note the results of this constructor can be somewhat unpredictable. * One might assume that new Expr(.1) is exactly equal to .1, but it is * actually equal to * .1000000000000000055511151231257827021181583404541015625. * This is so because .1 cannot be represented exactly as a double * (or, for that matter, as a binary fraction of any finite length). * Thus, the long value that is being passed in to the constructor is not * exactly equal to .1, appearances nonwithstanding. */ Expr(float f) { // check for valid numbers (i.e., not infinite and not NaN) if (!finite(f)) { std::cerr << " ERROR : constructed an invalid float! " << std::endl; if (AbortFlag) abort(); InvalidFlag = -1; } rep = new ConstDoubleRep(f); } /// constructor for double Expr(double d) { // check for valid numbers (i.e., not infinite and not NaN) if (!finite(d)) { std::cerr << " ERROR : constructed an invalid double! " << std::endl; if (AbortFlag) abort(); InvalidFlag = -2; } rep = new ConstDoubleRep(d); } /// constructor for BigInt Expr(const BigInt& I) { rep = new ConstRealRep(Real(I)); } /// constructor for BigRat Expr(const BigRat& R) { rep = new ConstRealRep(Real(R)); } /// constructor for BigFloat Expr(const BigFloat& F) { rep = new ConstRealRep(Real(F)); } /// constructor for const char* /** construct Expr from a string representation \a s * with precision \a prec. It is perfectly predictable: * new Expr(".1") is exactly equal to .1, as one would expect. Therefore, * it is generally recommended that the (String) constructor be used in * preference to the (double) constructor. */ Expr(const char *s, const extLong& prec = defInputDigits) { rep = new ConstRealRep(Real(s, prec)); } /// constructor for std::string Expr(const std::string& s, const extLong& prec = defInputDigits) { rep = new ConstRealRep(Real(s, prec)); } /// constructor for Real Expr(const Real &r) { rep = new ConstRealRep(r); } /// constructor for Polynomial node (n-th root) /** default value n=0 means the first positive root */ template Expr(const Polynomial& p, int n = 0) { rep = new ConstPolyRep(p, n); } /// constructor for Polynomial node (root in Interval I) template Expr(const Polynomial& p, const BFInterval& I) { rep = new ConstPolyRep(p, I); } /// constructor for ExprRep Expr(ExprRep* p) : rep(p) {} /// destructor ~Expr() { rep->decRefCount(); } //@} /// \name Assignment Operators //@{ /// = operator Expr& operator=(const Expr& e) { if (this == &e) return *this; e.rep->incRefCount(); rep->decRefCount(); rep = e.rep; return *this; } //@} /// \name Compound Assignment Operators //@{ /// += operator Expr& operator+=(const Expr& e) { ExprRep *old = rep; rep = new AddRep(rep, e.rep); old->decRefCount(); return *this; } /// -= operator Expr& operator-=(const Expr& e) { ExprRep *old = rep; rep = new SubRep(rep, e.rep); old->decRefCount(); return *this; } /// *= operator Expr& operator*=(const Expr& e) { ExprRep *old = rep; rep = new MultRep(rep, e.rep); old->decRefCount(); return *this; } /// /= operator Expr& operator/=(const Expr& e) { if ((e.rep)->getSign() == 0) { std::cerr << " ERROR : division by zero ! " << std::endl; if (AbortFlag) abort(); InvalidFlag = -3; } ExprRep *old = rep; rep = new DivRep(rep, e.rep); old->decRefCount(); return *this; } //@} /// \name Unary Minus, Increment and Decrement Operators //@{ /// unary minus Expr operator-() const { return Expr(new NegRep(rep)); } /// left increment operator (++i) Expr& operator++() { *this += 1; return *this; } /// right increment operator (i++) Expr operator++(int) { Expr t = *this; *this += 1; return t; } /// left decrement operator (--i) Expr& operator--() { *this -= 1; return *this; } /// right deccrement operator (i--) Expr operator--(int) { Expr t = *this; *this -= 1; return t; } //@} /// \name String Conversion Functions //@{ /// set value from const char* void fromString(const char* s, const extLong& prec = defInputDigits) { *this = Expr(s, prec); } /// convert to std::string /** give decimal string representation */ std::string toString(long prec=defOutputDigits, bool sci=false) const { return rep->toString(prec, sci); } //@} // /// \name Conversion Functions //@{ /// convert to \c int int intValue() const { return (this->approx(64, 1024)).intValue(); } /// convert to \c long long longValue() const { return (this->approx(64, 1024)).longValue(); } /// convert to \c float float floatValue() const { return (this->approx(53, 1024)).floatValue(); } /// convert to \c double /** chen: - use equivalent precision (rel:53, abs: 1024) as in IEEE double. enforce an evaluation in case before this has been done before casting. */ double doubleValue() const { return (this->approx(53, 1024)).doubleValue(); } /// convert to an interval defined by a pair of \c double /** If value is exact, the two \c double will coincide */ void doubleInterval(double & lb, double & ub) const; /// convert to \c BigInt (approximate it first!) BigFloat BigIntValue() const { return rep->BigIntValue(); } /// convert to \c BigRat (approximate it first!) BigFloat BigRatValue() const { return rep->BigRatValue(); } /// convert to \c BigFloat (approximate it first!) /** Ought to allow BigFloatValue() take an optional precision argument */ BigFloat BigFloatValue() const { return rep->BigFloatValue(); } //@} /// \name Approximation Function //@{ /// Compute approximation to combined precision [\a r, \a a]. /** Here is the definition of what this means: If e is the exact value and ee is the approximate value, then |e - ee| <= 2^{-a} or |e - ee| <= 2^{-r} |e|. */ const Real & approx(const extLong& relPrec = defRelPrec, const extLong& absPrec = defAbsPrec) const { return rep->getAppValue(relPrec, absPrec); } //@} /// \name Helper Functions //@{ /// get the sign int sign() const { return rep->getSign(); } /// is zero? bool isZero() const { return sign() == 0; } /// absolute value Expr abs() const { Expr x = (sign() >= 0) ? (*this) : -(*this); return x; } /// compare function int cmp(const Expr& e) const { return rep == e.rep ? 0 : SubRep(rep, e.rep).getSign(); } /// get exponent of current approximate value long getExponent() const { return BigFloatValue().exp(); } /// get mantissa of current approximate value BigInt getMantissa() const { return BigFloatValue().m(); } /// return rep pointer: ExprRep* getRep() const { return rep; } //@} /// return Expr(0) static const Expr& getZero(); public: /// \name Debug Helper Function //@{ /// debug function void debug(int mode = TREE_MODE, int level = DETAIL_LEVEL, int depthLimit = INT_MAX) const; //@} /// debug information levels enum {LIST_MODE, TREE_MODE, SIMPLE_LEVEL, DETAIL_LEVEL}; };// class Expr #define CORE_EXPR_ZERO Expr::getZero() /// I/O Stream operator<< inline std::ostream& operator<<(std::ostream& o, const Expr& e) { o << *(e.rep); return o; } /// I/O Stream operator>> inline std::istream& operator>>(std::istream& i, Expr& e) { Real rVal; i >> rVal; // precision is = defInputDigits if (i) e = rVal; // only assign when reading is successful. return i; } /// floor function BigInt floor(const Expr&, Expr&); /// power function Expr pow(const Expr&, unsigned long); /// addition inline Expr operator+(const Expr& e1, const Expr& e2) { return Expr(new AddRep(e1.rep, e2.rep)); } /// substraction inline Expr operator-(const Expr& e1, const Expr& e2) { return Expr(new SubRep(e1.rep, e2.rep)); } /// multiplication inline Expr operator*(const Expr& e1, const Expr& e2) { return Expr(new MultRep(e1.rep, e2.rep)); } /// division inline Expr operator/(const Expr& e1, const Expr& e2) { if (e2.sign() == 0) { std::cerr << " ERROR : division by zero ! " << std::endl; if (AbortFlag) abort(); InvalidFlag = -4; } return Expr(new DivRep(e1.rep, e2.rep)); } /// modulo operator inline Expr operator%(const Expr& e1, const Expr& e2) { Expr result; floor(e1/e2, result); return result; } /// operator == /** this is inefficient if you compare to zero: * e.g., if (e != 0) {...} use e.isZero() instead */ inline bool operator==(const Expr& e1, const Expr& e2) { return e1.cmp(e2) == 0; } /// operator != inline bool operator!=(const Expr& e1, const Expr& e2) { return e1.cmp(e2) != 0; } /// operator < inline bool operator< (const Expr& e1, const Expr& e2) { return e1.cmp(e2) < 0; } /// operator <= inline bool operator<=(const Expr& e1, const Expr& e2) { return e1.cmp(e2) <= 0; } /// operator < inline bool operator> (const Expr& e1, const Expr& e2) { return e1.cmp(e2) > 0; } /// operator >= inline bool operator>=(const Expr& e1, const Expr& e2) { return e1.cmp(e2) >= 0; } /// return sign inline int sign(const Expr& e) { return e.sign(); } /// is zero? inline bool isZero(const Expr& e) { return e.isZero(); } /// compare /** compare two Expr \a e1 and \a e2, return * \retval -1 if e1 < e2, * \retval 0 if e1 = e2, * \retval 1 if e1 > e2. */ inline int cmp(const Expr& e1, const Expr& e2) { return e1.cmp(e2); } /// absolute value inline Expr abs(const Expr& x) { return x.abs(); } /// absolute value (same as abs) inline Expr fabs(const Expr& x) { return abs(x); } /// floor inline BigInt floor(const Expr& e) { Expr tmp; return floor(e, tmp); } /// ceiling inline BigInt ceil(const Expr& e) { return -floor(-e); } /// power inline Expr power(const Expr& e, unsigned long p) { return pow(e, p); } /// divisibility predicate inline bool isDivisible(const Expr& e1, const Expr& e2) { Expr result; floor(e1/e2, result); return (result.sign() == 0); } /// square root inline Expr sqrt(const Expr& e) { if (e.sign() < 0) { std::cerr << " ERROR : sqrt of negative value ! " << std::endl; if (AbortFlag) abort(); InvalidFlag = -5; } return Expr(new SqrtRep(e.rep)); } /// helper function for constructing Polynomial node (n-th node) template inline Expr rootOf(const Polynomial& p, int n = 0) { return Expr(p, n); } /// helper function for constructing Polynomial node template inline Expr rootOf(const Polynomial& p, const BFInterval& I) { return Expr(p, I); } /// constructor for Polynomial node of the form x^m - n (i.e., radicals) template inline Expr radical(const NT& n, int m) { Polynomial Q(m); BFInterval I(0, n); Q.setCoeff(0, -n); Q.setCoeff(m, 1); return Expr(new ConstPolyRep(Q, I)); } #include // We include this file here and not from inside Poly.h, // because otherwise VC++.net2003 can't compile Expr.cpp CORE_END_NAMESPACE #endif