rational-native.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file rational-native.cpp
00004  *
00005  * \brief Implementation of class Rational using native (bounded
00006  * precision) computer arithmetic
00007  * 
00008  * Author: Sergey Berezin
00009  * 
00010  * Created: Mon Jul 28 12:18:03 2003
00011  *
00012  * <hr>
00013  * License to use, copy, modify, sell and/or distribute this software
00014  * and its documentation for any purpose is hereby granted without
00015  * royalty, subject to the terms and conditions defined in the \ref
00016  * LICENSE file provided with this distribution.
00017  * 
00018  * <hr>
00019  *
00020  */
00021 /*****************************************************************************/
00022 
00023 #ifdef RATIONAL_NATIVE
00024 
00025 #include "compat_hash_set.h"
00026 #include "rational.h"
00027 // For atol() (ASCII to long)
00028 #include <stdlib.h>
00029 #include <errno.h>
00030 #include <sstream>
00031 
00032 #define OVERFLOW_MSG "\nThis is NOT a bug, but an explicit feature to preserve soundness\nwhen CVC3 uses native computer arithmetic (finite precision).  To\navoid this type of errors, please recompile CVC3 with GMP library."
00033 
00034 namespace CVC3 {
00035 
00036   using namespace std;
00037 
00038   //! Add two integers and check for overflows
00039   static long int plus(long int x, long int y) {
00040     long int res = x+y;
00041     FatalAssert(((x > 0) != (y > 0)) || ((x > 0) == (res > 0)),
00042                 "plus(x,y): arithmetic overflow" OVERFLOW_MSG);
00043     return res;
00044   }
00045 
00046   //! Unary minus which checks for overflows
00047   static long int uminus(long int x) {
00048     FatalAssert(x == 0 || x != -x, "uminus(x): arithmetic overflow"
00049                 OVERFLOW_MSG);
00050     return -x;
00051   }
00052 
00053   //! Multiply two integers and check for overflows
00054   static long int mult(long int x, long int y) {
00055     long int res = x*y;
00056     FatalAssert(x==0 || res/x == y, "mult(x,y): arithmetic overflow"
00057                 OVERFLOW_MSG);
00058     return res;
00059   }
00060 
00061   //! Compute GCD using Euclid's algorithm (from Aaron Stump's code)
00062   static long int gcd(long int n1, long int n2) {
00063     DebugAssert(n1!=0 && n2!=0,
00064     "gcd("+int2string(n1)+", "+int2string(n2)+"): bad args");
00065   // First, make the arguments positive
00066   if(n1 < 0) n1 = uminus(n1);
00067   if(n2 < 0) n2 = uminus(n2);
00068 
00069   if (n1 < n2) {
00070     long int tmp = n1;
00071     n1 = n2;
00072     n2 = tmp;
00073   }
00074 
00075   // at this point, n1 >= n2
00076   long int r = n1 % n2;
00077   if (!r)
00078     return n2;
00079 
00080   return gcd(n2, r);
00081 }
00082 
00083   //! Compute LCM
00084   static long int lcm(long int n1, long int n2) {
00085     long int g = gcd(n1,n2);
00086     return mult(n1/g, n2);
00087   }
00088 
00089   // Implementation of the forward-declared internal class
00090   class Rational::Impl {
00091     long int d_num; //!< Numerator
00092     long int d_denom; //!< Denominator
00093     //! Make the rational number canonical
00094     void canonicalize();
00095   public:
00096     //! Default Constructor
00097     Impl(): d_num(0), d_denom(1) { }
00098     //! Copy constructor
00099     Impl(const Impl &x) : d_num(x.d_num), d_denom(x.d_denom) { }
00100     //! Constructor from a pair of integers
00101     Impl(long int n, long int d): d_num(n), d_denom(d) { canonicalize(); }
00102     //! Constructor from a string
00103     Impl(const string &n, int base);
00104     //! Constructor from a pair of strings
00105     Impl(const string &n, const string& d, int base);
00106     // Destructor
00107     virtual ~Impl() { }
00108     //! Get numerator
00109     long int getNum() const { return d_num; }
00110     //! Get denominator
00111     long int getDen() const { return d_denom; }
00112 
00113     //! Unary minus
00114     Impl operator-() const;
00115 
00116     //! Equality
00117     friend bool operator==(const Impl& x, const Impl& y) {
00118       return (x.d_num == y.d_num && x.d_denom == y.d_denom);
00119     }
00120     //! Dis-equality
00121     friend bool operator!=(const Impl& x, const Impl& y) {
00122       return (x.d_num != y.d_num || x.d_denom != y.d_denom);
00123     }
00124     /*! 
00125      * Compare x=n1/d1 and y=n2/d2 as n1*f2 < n2*f1, where f1=d1/f,
00126      * f2=d2/f, and f=lcm(d1,d2)
00127      */
00128     friend bool operator<(const Impl& x, const Impl& y) {
00129       Impl diff(x-y);
00130       return diff.d_num < 0;
00131     }
00132 
00133     friend bool operator<=(const Impl& x, const Impl& y) {
00134       return (x == y || x < y);
00135     }
00136 
00137     friend bool operator>(const Impl& x, const Impl& y) {
00138       Impl diff(x-y);
00139       return diff.d_num > 0;
00140     }
00141 
00142     friend bool operator>=(const Impl& x, const Impl& y) {
00143       return (x == y || x > y);
00144     }
00145 
00146     /*! Addition of x=n1/d1 and y=n2/d2: n1*g2 + n2*g1, where g1=d1/g,
00147      * g2=d2/g, and g=lcm(d1,d2)
00148      */
00149     friend Impl operator+(const Impl& x, const Impl& y) {
00150       long int d1(x.getDen()), d2(y.getDen());
00151       long int f(lcm(d1,d2)), f1(f/d1), f2(f/d2);
00152       long int n = plus(mult(x.getNum(), f1),  mult(y.getNum(), f2));
00153       return Impl(n, f);
00154     }
00155 
00156     friend Impl operator-(const Impl& x, const Impl& y) {
00157       TRACE("rational", "operator-(", x, ", "+y.toString()+")");
00158       long int d1(x.getDen()), d2(y.getDen());
00159       long int f(lcm(d1,d2)), f1(f/d1), f2(f/d2);
00160       long int n = plus(mult(x.getNum(), f1),  uminus(mult(y.getNum(), f2)));
00161       Impl res(n, f);
00162       TRACE("rational", "  => ", res, "");
00163       return res;
00164     }
00165 
00166     /*! 
00167      * Multiplication of x=n1/d1, y=n2/d2:
00168      * (n1/g1)*(n2/g2)/(d1/g2)*(d2/g1), where g1=gcd(n1,d2) and
00169      * g2=gcd(n2,d1)
00170      */
00171     friend Impl operator*(const Impl& x, const Impl& y) {
00172       long int n1(x.getNum()), d1(x.getDen()), n2(y.getNum()), d2(y.getDen());
00173       long int g1(n1? gcd(n1,d2) : 1), g2(n2? gcd(n2,d1) : 1);
00174       long int n(mult(n1/g1, n2/g2)), d(mult(d1/g2, d2/g1));
00175       return Impl(n,d);
00176     }
00177 
00178     /*! 
00179      * Division of x=n1/d1, y=n2/d2:
00180      * (n1/g1)*(d2/g2)/(d1/g2)*(n2/g1), where g1=gcd(n1,n2) and
00181      * g2=gcd(d1,d2)
00182      */
00183     friend Impl operator/(const Impl& x, const Impl& y) {
00184       long int n1(x.getNum()), d1(x.getDen()), n2(y.getNum()), d2(y.getDen());
00185       DebugAssert(n2 != 0, "Impl::operator/: divisor is 0");
00186       long int g1(n1? gcd(n1,n2) : 1), g2(gcd(d1,d2));
00187       long int n(n1? mult(n1/g1, d2/g2) : 0), d(n1? mult(d1/g2, n2/g1) : 1);
00188       return Impl(n,d);
00189     }
00190 
00191     friend Impl operator%(const Impl& x, const Impl& y) {
00192       DebugAssert(x.getDen() == 1 && y.getDen() == 1,
00193       "Impl % Impl: x and y must be integers");
00194       return Impl(x.getNum() % y.getNum(), 1);
00195     }
00196 
00197     //! Print to string
00198     string toString(int base = 10) const {
00199       ostringstream ss;
00200       if (d_num == 0) ss << "0";
00201       else if (base == 10) {
00202         ss << d_num;
00203         if (d_denom != 1)
00204           ss << "/" << d_denom;
00205       }
00206       else {
00207         vector<int> vec;
00208         long num = d_num;
00209         while (num) {
00210           vec.push_back(num % base);
00211           num = num / base;
00212         }
00213         while (!vec.empty()) {
00214           if (base > 10 && vec.back() > 10) {
00215             ss << (char)('A' + (vec.back()-10));
00216           }
00217           else ss << vec.back();
00218           vec.pop_back();
00219         }
00220         if(d_denom != 1) {
00221           ss << "/";
00222           if (d_denom == 0) ss << "0";
00223           else {
00224             num = d_denom;
00225             while (num) {
00226               vec.push_back(num % base);
00227               num = num / base;
00228             }
00229             while (!vec.empty()) {
00230               if (base > 10 && vec.back() > 10) {
00231                 ss << (char)('A' + (vec.back()-10));
00232               }
00233               else ss << vec.back();
00234               vec.pop_back();
00235             }
00236           }
00237         }
00238       }
00239       return(ss.str());
00240     }
00241 
00242     //! Printing to ostream
00243     friend ostream& operator<<(ostream& os, const Rational::Impl& n) {
00244       return os << n.toString();
00245     }
00246       
00247   };
00248 
00249   // Make the rational number canonical
00250   void Rational::Impl::canonicalize() {
00251     DebugAssert(d_denom != 0,
00252                 "Rational::Impl::canonicalize: bad denominator: "
00253                 +int2string(d_denom));
00254     if(d_num == 0) {
00255       d_denom = 1;
00256     } else {
00257       if(d_denom < 0) {
00258   d_num = uminus(d_num);
00259   d_denom = uminus(d_denom);
00260       }
00261       long int d = gcd(d_num, d_denom);
00262       if(d != 1) {
00263   d_num /= d;
00264   d_denom /= d;
00265       }
00266     }
00267   }
00268 
00269   // Constructor from a string
00270   Rational::Impl::Impl(const string &n, int base) {
00271     size_t i, iend;
00272     for(i=0,iend=n.size(); i<iend && n[i] != '/'; ++i);
00273     if(i<iend)
00274       // Found slash at i
00275       *this = Impl(n.substr(0,i-1), n.substr(i+1,iend-1), base);
00276     else
00277       *this = Impl(n, "1", base);
00278     canonicalize();
00279   }
00280   // Constructor from a pair of strings
00281   Rational::Impl::Impl(const string &n, const string& d, int base) {
00282     d_num = strtol(n.c_str(), NULL, base);
00283     FatalAssert(d_num != LONG_MIN &&  d_num != LONG_MAX,
00284                 "Rational::Impl(string, string): arithmetic overflow:"
00285                 "n = "+n+", d="+d+", base="+int2string(base)
00286                 +OVERFLOW_MSG);
00287     d_denom = strtol(d.c_str(), NULL, base);
00288     FatalAssert(d_denom != LONG_MIN &&  d_denom != LONG_MAX,
00289                 "Rational::Impl(string, string): arithmetic overflow:"
00290                 "n = "+n+", d="+d+", base="+int2string(base)
00291                 +OVERFLOW_MSG);
00292     canonicalize();
00293   }
00294 
00295   Rational::Impl Rational::Impl::operator-() const {
00296     return Impl(uminus(d_num), d_denom);
00297   }
00298 
00299 
00300   //! Default constructor
00301   Rational::Rational() : d_n(new Impl) {
00302 #ifdef _DEBUG_RATIONAL_
00303     int &num_created = getCreated();
00304     num_created++;
00305     printStats();
00306 #endif
00307   }
00308   //! Copy constructor
00309   Rational::Rational(const Rational &n) : d_n(new Impl(*n.d_n)) {
00310 #ifdef _DEBUG_RATIONAL_
00311     int &num_created = getCreated();
00312     num_created++;
00313     printStats();
00314 #endif
00315   }
00316 
00317   //! Private constructor
00318   Rational::Rational(const Impl& t): d_n(new Impl(t)) {
00319 #ifdef _DEBUG_RATIONAL_
00320     int &num_created = getCreated();
00321     num_created++;
00322     printStats();
00323 #endif
00324   }
00325   Rational::Rational(int n, int d): d_n(new Impl(n, d)) {
00326 #ifdef _DEBUG_RATIONAL_
00327     int &num_created = getCreated();
00328     num_created++;
00329     printStats();
00330 #endif
00331   }
00332   // Constructors from strings
00333   Rational::Rational(const char* n, int base)
00334     : d_n(new Impl(string(n), base)) {
00335 #ifdef _DEBUG_RATIONAL_
00336     int &num_created = getCreated();
00337     num_created++;
00338     printStats();
00339 #endif
00340   }
00341   Rational::Rational(const string& n, int base)
00342     : d_n(new Impl(n, base)) {
00343 #ifdef _DEBUG_RATIONAL_
00344     int &num_created = getCreated();
00345     num_created++;
00346     printStats();
00347 #endif
00348   }
00349   Rational::Rational(const char* n, const char* d, int base)
00350     : d_n(new Impl(string(n), string(d), base)) {
00351 #ifdef _DEBUG_RATIONAL_
00352     int &num_created = getCreated();
00353     num_created++;
00354     printStats();
00355 #endif
00356   }
00357   Rational::Rational(const string& n, const string& d, int base)
00358     : d_n(new Impl(n, d, base)) {
00359 #ifdef _DEBUG_RATIONAL_
00360     int &num_created = getCreated();
00361     num_created++;
00362     printStats();
00363 #endif
00364   }
00365   // Destructor
00366   Rational::~Rational() {
00367     delete d_n;
00368 #ifdef _DEBUG_RATIONAL_
00369     int &num_deleted = getDeleted();
00370     num_deleted++;
00371     printStats();
00372 #endif
00373   }
00374 
00375   // Get components
00376   Rational Rational::getNumerator() const
00377     { return Rational(Impl(d_n->getNum(), 1)); }
00378   Rational Rational::getDenominator() const
00379     { return Rational(Impl(d_n->getDen(), 1)); }
00380 
00381   bool Rational::isInteger() const { return 1 == d_n->getDen(); }
00382 
00383   // Assignment
00384   Rational& Rational::operator=(const Rational& n) {
00385     if(this == &n) return *this;
00386     delete d_n;
00387     d_n = new Impl(*n.d_n);
00388     return *this;
00389   }
00390 
00391   ostream &operator<<(ostream &os, const Rational &n) {
00392     return(os << n.toString());
00393   }
00394 
00395 
00396   // Check that argument is an int and print an error message otherwise
00397 
00398   static void checkInt(const Rational& n, const string& funName) {
00399     DebugAssert(n.isInteger(),
00400     ("CVC3::Rational::" + funName
00401      + ": argument is not an integer: " + n.toString()).c_str());
00402   }
00403 
00404     /* Computes gcd and lcm on *integer* values. Result is always a
00405        positive integer.  In this implementation, it is guaranteed by
00406        GMP. */
00407 
00408   Rational gcd(const Rational &x, const Rational &y) {
00409     checkInt(x, "gcd(*x*,y)");
00410     checkInt(y, "gcd(x,*y*)");
00411     return Rational(Rational::Impl(gcd(x.d_n->getNum(), y.d_n->getNum()), 1));
00412   }
00413  
00414   Rational gcd(const vector<Rational> &v) {
00415     long int g(1);
00416     if(v.size() > 0) {
00417       checkInt(v[0], "gcd(vector<Rational>[0])");
00418       g = v[0].d_n->getNum();
00419     }
00420     for(size_t i=1; i<v.size(); i++) {
00421       checkInt(v[i], "gcd(vector<Rational>)");
00422       if(g == 0) g = v[i].d_n->getNum();
00423       else if(v[i].d_n->getNum() != 0)
00424   g = gcd(g, v[i].d_n->getNum());
00425     }
00426     return Rational(Rational::Impl(g,1));
00427   }
00428 
00429   Rational lcm(const Rational &x, const Rational &y) {
00430     long int g;
00431     checkInt(x, "lcm(*x*,y)");
00432     checkInt(y, "lcm(x,*y*)");
00433     g = lcm(x.d_n->getNum(), y.d_n->getNum());
00434     return Rational(Rational::Impl(g, 1));
00435   }
00436 
00437   Rational lcm(const vector<Rational> &v) {
00438     long int g(1);
00439     for(size_t i=0; i<v.size(); i++) {
00440       checkInt(v[i], "lcm(vector<Rational>)");
00441       if(v[i].d_n->getNum() != 0)
00442   g = lcm(g, v[i].d_n->getNum());
00443     }
00444     return Rational(Rational::Impl(g,1));
00445   }
00446 
00447   Rational abs(const Rational &x) {
00448     long int n(x.d_n->getNum());
00449     if(n>=0) return x;
00450     return Rational(Rational::Impl(-n, x.d_n->getDen()));
00451   }
00452 
00453   Rational floor(const Rational &x) {
00454     if(x.d_n->getDen() == 1) return x;
00455     long int n = x.d_n->getNum();
00456     long int nAbs = (n<0)? uminus(n) : n;
00457     long int q = nAbs / x.d_n->getDen();
00458     if(n < 0) q = plus(uminus(q), -1);
00459     return Rational(Rational::Impl(q,1));
00460   }
00461 
00462   Rational ceil(const Rational &x) {
00463     if(x.d_n->getDen() == 1) return x;
00464     long int n = x.d_n->getNum();
00465     long int nAbs = (n<0)? -n : n;
00466     long int q = nAbs / x.d_n->getDen();
00467     if(n > 0) q = plus(q, 1);
00468     else q = uminus(q);
00469     return Rational(Rational::Impl(q,1));
00470   }
00471 
00472   Rational mod(const Rational &x, const Rational &y) {
00473     checkInt(x, "mod(*x*,y)");
00474     checkInt(y, "mod(x,*y*)");
00475     long int r = x.d_n->getNum() % y.d_n->getNum();
00476     return(Rational(Rational::Impl(r,1)));
00477   }
00478   
00479   string Rational::toString(int base) const {
00480     return(d_n->toString(base));
00481   }
00482 
00483   size_t Rational::hash() const {
00484     std::hash<const char *> h;
00485     return h(toString().c_str());
00486   }
00487   
00488   void Rational::print() const {
00489     cout << (*this) << endl;
00490   }
00491 
00492   // Unary minus
00493   Rational Rational::operator-() const {
00494     return Rational(Rational::Impl(-(d_n->getNum()), d_n->getDen()));
00495   }
00496   
00497   Rational &Rational::operator+=(const Rational &n2) {
00498     *this = (*this) + n2;
00499     return *this;
00500   }
00501   
00502   Rational &Rational::operator-=(const Rational &n2) {
00503     *this = (*this) - n2;
00504     return *this;
00505   }
00506   
00507   Rational &Rational::operator*=(const Rational &n2) {
00508     *this = (*this) * n2;
00509     return *this;
00510   }
00511   
00512   Rational &Rational::operator/=(const Rational &n2) {
00513     *this = (*this) / n2;
00514     return *this;
00515   }
00516 
00517   int Rational::getInt() const {
00518     checkInt(*this, "getInt()");
00519     long int res = d_n->getNum();
00520     FatalAssert(res >= INT_MIN && res <= INT_MAX,
00521                 "Rational::getInt(): overflow on "+toString());
00522     return (int)res;
00523   }
00524 
00525   unsigned int Rational::getUnsigned() const {
00526     checkInt(*this, "getUnsigned()");
00527     long int res = d_n->getNum();
00528     FatalAssert(res >= 0 && res <= (long int)UINT_MAX,
00529                 "Rational::getUnsigned(): overflow on "+toString());
00530     return (unsigned int)res;
00531   }
00532 
00533 #ifdef _DEBUG_RATIONAL_
00534   void Rational::printStats() {
00535       int &num_created = getCreated();
00536       int &num_deleted = getDeleted();
00537       if(num_created % 1000 == 0 || num_deleted % 1000 == 0) {
00538   std::cerr << "Rational(" << *d_n << "): created " << num_created
00539       << ", deleted " << num_deleted
00540       << ", currently alive " << num_created-num_deleted
00541       << std::endl;
00542       }
00543     }
00544 #endif
00545 
00546     bool operator==(const Rational &n1, const Rational &n2) {
00547       return(*n1.d_n == *n2.d_n);
00548     }
00549 
00550     bool operator<(const Rational &n1, const Rational &n2) {
00551       return(*n1.d_n < *n2.d_n);
00552     }
00553 
00554     bool operator<=(const Rational &n1, const Rational &n2) {
00555       return(*n1.d_n <= *n2.d_n);
00556     }
00557 
00558     bool operator>(const Rational &n1, const Rational &n2) {
00559       return(*n1.d_n > *n2.d_n);
00560     }
00561 
00562     bool operator>=(const Rational &n1, const Rational &n2) {
00563       return(*n1.d_n >= *n2.d_n);
00564     }
00565 
00566     bool operator!=(const Rational &n1, const Rational &n2) {
00567       return(*n1.d_n != *n2.d_n);
00568     }
00569 
00570     Rational operator+(const Rational &n1, const Rational &n2) {
00571       return Rational(Rational::Impl(*n1.d_n + *n2.d_n));
00572     }
00573 
00574     Rational operator-(const Rational &n1, const Rational &n2) {
00575       return Rational(Rational::Impl((*n1.d_n) - (*n2.d_n)));
00576     }
00577 
00578     Rational operator*(const Rational &n1, const Rational &n2) {
00579       return Rational(Rational::Impl((*n1.d_n) * (*n2.d_n)));
00580     }
00581 
00582     Rational operator/(const Rational &n1, const Rational &n2) {
00583       return Rational(Rational::Impl(*n1.d_n / *n2.d_n));
00584     }
00585 
00586     Rational operator%(const Rational &n1, const Rational &n2) {
00587       return Rational(Rational::Impl(*n1.d_n + *n2.d_n));
00588     }
00589 
00590 }; /* close namespace */
00591 
00592 #endif

Generated on Tue Jul 3 14:33:38 2007 for CVC3 by  doxygen 1.5.1