rational.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file rational.cpp
00004  * 
00005  * Author: Sergey Berezin
00006  * 
00007  * Created: Dec 12 22:00:18 GMT 2002
00008  *
00009  * <hr>
00010  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00011  * Junior University and by New York University. 
00012  *
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.  In particular:
00017  *
00018  * - The above copyright notice and this permission notice must appear
00019  * in all copies of the software and related documentation.
00020  *
00021  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00022  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00023  * 
00024  * <hr>
00025  * 
00026  */
00027 /*****************************************************************************/
00028 // Class: Rational
00029 // Author: Sergey Berezin, 12/12/2002 (adapted from Bignum)
00030 //
00031 // Description: Implementation of class Rational.  See comments in
00032 // rational.h file.
00033 ///////////////////////////////////////////////////////////////////////////////
00034 
00035 #ifdef RATIONAL_GMPXX
00036 
00037 #include <gmpxx.h>
00038 #include "compat_hash_set.h"
00039 #include "rational.h"
00040 
00041 namespace CVCL {
00042 
00043   using namespace std;
00044 
00045   // Implementation of the forward-declared internal class
00046   class Rational::Impl : public mpq_class {
00047   public:
00048     //    mpz_class _n;
00049     // Constructors
00050     Impl() : mpq_class() { }
00051     // Constructor from integer
00052     //    Impl(const mpz_class &x) : mpq_class(x) { }
00053     // Constructor from rational
00054     Impl(const mpq_class &x) : mpq_class(x) { }
00055     // Copy constructor
00056     Impl(const Impl &x) : mpq_class(x) { }
00057     // From pair of integers / strings
00058     Impl(int n, int d) : mpq_class(n,d) { canonicalize(); }
00059     Impl(const mpz_class& n, const mpz_class& d)
00060       : mpq_class(n,d) { canonicalize(); }
00061     // From string(s)
00062     Impl(const string &n, int base): mpq_class(n, base) { canonicalize(); }
00063     Impl(const string &n, const string& d, int base)
00064       : mpq_class(n + "/" + d, base)  { canonicalize(); }
00065     // Destructor
00066     virtual ~Impl() { }
00067     // Getting numerator and denominator.  DON NOT ASSIGN to the result
00068     mpz_class getNum() { return get_num(); }
00069     mpz_class getDen() { return get_den(); }
00070   };
00071 
00072   // Constructors
00073   Rational::Rational() : d_n(new Impl) {
00074 #ifdef _DEBUG_RATIONAL_
00075     int &num_created = getCreated();
00076     num_created++;
00077     printStats();
00078 #endif
00079   }
00080     // Copy constructor
00081   Rational::Rational(const Rational &n) : d_n(new Impl(*n.d_n)) {
00082 #ifdef _DEBUG_RATIONAL_
00083     int &num_created = getCreated();
00084     num_created++;
00085     printStats();
00086 #endif
00087   }
00088 
00089   // Private constructor
00090   Rational::Rational(const Impl& t): d_n(new Impl(t)) {
00091 #ifdef _DEBUG_RATIONAL_
00092     int &num_created = getCreated();
00093     num_created++;
00094     printStats();
00095 #endif
00096   }
00097   Rational::Rational(int n, int d): d_n(new Impl(n, d)) {
00098 #ifdef _DEBUG_RATIONAL_
00099     int &num_created = getCreated();
00100     num_created++;
00101     printStats();
00102 #endif
00103   }
00104   // Constructors from strings
00105   Rational::Rational(const char* n, int base)
00106     : d_n(new Impl(string(n), base)) {
00107 #ifdef _DEBUG_RATIONAL_
00108     int &num_created = getCreated();
00109     num_created++;
00110     printStats();
00111 #endif
00112   }
00113   Rational::Rational(const string& n, int base)
00114     : d_n(new Impl(n, base)) {
00115 #ifdef _DEBUG_RATIONAL_
00116     int &num_created = getCreated();
00117     num_created++;
00118     printStats();
00119 #endif
00120   }
00121   Rational::Rational(const char* n, const char* d, int base)
00122     : d_n(new Impl(string(n), string(d), base)) {
00123 #ifdef _DEBUG_RATIONAL_
00124     int &num_created = getCreated();
00125     num_created++;
00126     printStats();
00127 #endif
00128   }
00129   Rational::Rational(const string& n, const string& d, int base)
00130     : d_n(new Impl(n, d, base)) {
00131 #ifdef _DEBUG_RATIONAL_
00132     int &num_created = getCreated();
00133     num_created++;
00134     printStats();
00135 #endif
00136   }
00137   // Destructor
00138   Rational::~Rational() {
00139     delete d_n;
00140 #ifdef _DEBUG_RATIONAL_
00141     int &num_deleted = getDeleted();
00142     num_deleted++;
00143     printStats();
00144 #endif
00145   }
00146 
00147   // Get components
00148   Rational Rational::getNumerator() const
00149     { return Rational(Impl(d_n->getNum(), 1)); }
00150   Rational Rational::getDenominator() const
00151     { return Rational(Impl(d_n->getDen(), 1)); }
00152 
00153   bool Rational::isInteger() const { return 1 == d_n->getDen(); }
00154 
00155   // Assignment
00156   Rational& Rational::operator=(const Rational& n) {
00157     if(this == &n) return *this;
00158     delete d_n;
00159     d_n = new Impl(*n.d_n);
00160     return *this;
00161   }
00162 
00163   ostream &operator<<(ostream &os, const Rational &n) {
00164     return(os << n.toString());
00165   }
00166 
00167 
00168   // Check that argument is an int and print an error message otherwise
00169 
00170   static void checkInt(const Rational& n, const string& funName) {
00171     DebugAssert(n.isInteger(),
00172                 ("CVCL::Rational::" + funName
00173                  + ": argument is not an integer: " + n.toString()).c_str());
00174   }
00175 
00176     /* Computes gcd and lcm on *integer* values. Result is always a
00177        positive integer.  In this implementation, it is guaranteed by
00178        GMP. */
00179 
00180   Rational gcd(const Rational &x, const Rational &y) {
00181     mpz_class g;
00182     checkInt(x, "gcd(*x*,y)");
00183     checkInt(y, "gcd(x,*y*)");
00184     mpz_gcd(g.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t());
00185     return Rational(Rational::Impl(g,1));
00186   }
00187  
00188   Rational gcd(const vector<Rational> &v) {
00189     mpz_class g(1);
00190     if(v.size() > 0) {
00191       checkInt(v[0], "gcd(vector<Rational>[0])");
00192       g = v[0].d_n->getNum();
00193     }
00194     for(unsigned i=1; i<v.size(); i++) {
00195       checkInt(v[i], "gcd(vector<Rational>)");
00196       if(*v[i].d_n != 0)
00197         mpz_gcd(g.get_mpz_t(), g.get_mpz_t(), v[i].d_n->get_num_mpz_t());
00198     }
00199     return Rational(Rational::Impl(g,1));
00200   }
00201 
00202   Rational lcm(const Rational &x, const Rational &y) {
00203     mpz_class g;
00204     checkInt(x, "lcm(*x*,y)");
00205     checkInt(y, "lcm(x,*y*)");
00206     mpz_lcm(g.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t());
00207     return Rational(Rational::Impl(g, 1));
00208   }
00209 
00210   Rational lcm(const vector<Rational> &v) {
00211     mpz_class g(1);
00212     for(unsigned i=0; i<v.size(); i++) {
00213       checkInt(v[i], "lcm(vector<Rational>)");
00214       if(*v[i].d_n != 0)
00215         mpz_lcm(g.get_mpz_t(), g.get_mpz_t(), v[i].d_n->get_num_mpz_t());
00216     }
00217     return Rational(Rational::Impl(g,1));
00218   }
00219 
00220   Rational abs(const Rational &x) {
00221     return Rational(Rational::Impl(abs(*x.d_n)));
00222   }
00223 
00224   Rational floor(const Rational &x) {
00225     mpz_class q;
00226     mpz_fdiv_q(q.get_mpz_t(), x.d_n->get_num_mpz_t(), x.d_n->get_den_mpz_t());
00227     return Rational(Rational::Impl(q,1));
00228   }
00229 
00230   Rational ceil(const Rational &x) {
00231     mpz_class q;
00232     mpz_cdiv_q(q.get_mpz_t(), x.d_n->get_num_mpz_t(), x.d_n->get_den_mpz_t());
00233     return Rational(Rational::Impl(q,1));
00234   }
00235 
00236   Rational mod(const Rational &x, const Rational &y) {
00237     checkInt(x, "mod(*x*,y)");
00238     checkInt(y, "mod(x,*y*)");
00239     mpz_class r;
00240     mpz_mod(r.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t());
00241     return(Rational(Rational::Impl(r,1)));
00242   }
00243 
00244 
00245   string Rational::toString(int base) const {
00246     char *tmp = mpq_get_str(NULL, base, d_n->get_mpq_t());
00247     string res(tmp);
00248 //    delete tmp;
00249     free(tmp);
00250     return(res);
00251   }
00252 
00253   size_t Rational::hash() const {
00254     std::hash<const char *> h;
00255     return h(toString().c_str());
00256   }
00257   
00258   void Rational::print() const {
00259     cout << (*d_n) << endl;
00260   }
00261 
00262   // Unary minus
00263   Rational Rational::operator-() const {
00264     return Rational(Rational::Impl(- (*d_n)));
00265   }
00266   
00267   Rational &Rational::operator+=(const Rational &n2) {
00268     *d_n += (*n2.d_n);
00269     return *this;
00270   }
00271   
00272   Rational &Rational::operator-=(const Rational &n2) {
00273     *d_n -= (*n2.d_n);
00274     return *this;
00275   }
00276   
00277   Rational &Rational::operator*=(const Rational &n2) {
00278     *d_n *= (*n2.d_n);
00279     return *this;
00280   }
00281   
00282   Rational &Rational::operator/=(const Rational &n2) {
00283     *d_n /= (*n2.d_n);
00284     return *this;
00285   }
00286 
00287   int Rational::getInt() const {
00288     checkInt(*this, "getInt()");
00289     return mpz_get_si(d_n->get_num_mpz_t());
00290   }
00291 
00292   unsigned int Rational::getUnsigned() const {
00293     checkInt(*this, "getUnsigned()");
00294     return mpz_get_ui(d_n->get_num_mpz_t());
00295   }
00296 
00297 #ifdef _DEBUG_RATIONAL_
00298   void Rational::printStats() {
00299       int &num_created = getCreated();
00300       int &num_deleted = getDeleted();
00301       if(num_created % 1000 == 0 || num_deleted % 1000 == 0) {
00302         std::cerr << "Rational(" << *d_n << "): created " << num_created
00303                   << ", deleted " << num_deleted
00304                   << ", currently alive " << num_created-num_deleted
00305                   << std::endl;
00306       }
00307     }
00308 #endif
00309 
00310     bool operator==(const Rational &n1, const Rational &n2) {
00311       return(*n1.d_n == *n2.d_n);
00312     }
00313 
00314     bool operator<(const Rational &n1, const Rational &n2) {
00315       return(*n1.d_n < *n2.d_n);
00316     }
00317 
00318     bool operator<=(const Rational &n1, const Rational &n2) {
00319       return(*n1.d_n <= *n2.d_n);
00320     }
00321 
00322     bool operator>(const Rational &n1, const Rational &n2) {
00323       return(*n1.d_n > *n2.d_n);
00324     }
00325 
00326     bool operator>=(const Rational &n1, const Rational &n2) {
00327       return(*n1.d_n >= *n2.d_n);
00328     }
00329 
00330     bool operator!=(const Rational &n1, const Rational &n2) {
00331       return(*n1.d_n != *n2.d_n);
00332     }
00333 
00334     Rational operator+(const Rational &n1, const Rational &n2) {
00335       return Rational(Rational::Impl(*n1.d_n + *n2.d_n));
00336     }
00337 
00338     Rational operator-(const Rational &n1, const Rational &n2) {
00339       return Rational(Rational::Impl((*n1.d_n) - (*n2.d_n)));
00340     }
00341 
00342     Rational operator*(const Rational &n1, const Rational &n2) {
00343       return Rational(Rational::Impl((*n1.d_n) * (*n2.d_n)));
00344     }
00345 
00346     Rational operator/(const Rational &n1, const Rational &n2) {
00347       return Rational(Rational::Impl(*n1.d_n / *n2.d_n));
00348     }
00349 
00350     Rational operator%(const Rational &n1, const Rational &n2) {
00351       return Rational(Rational::Impl(*n1.d_n + *n2.d_n));
00352     }
00353 
00354 }; /* close namespace */
00355 
00356 #endif

Generated on Thu Apr 13 16:57:32 2006 for CVC Lite by  doxygen 1.4.4