rational-gmp.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file rational-gmp.cpp
00004  *
00005  * \brief Implementation of class Rational using GMP library (C interface)
00006  * 
00007  * Author: Sergey Berezin
00008  * 
00009  * Created: Mon Aug  4 10:06:04 2003
00010  *
00011  * <hr>
00012  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00013  * Junior University and by New York University. 
00014  *
00015  * License to use, copy, modify, sell and/or distribute this software
00016  * and its documentation for any purpose is hereby granted without
00017  * royalty, subject to the terms and conditions defined in the \ref
00018  * LICENSE file provided with this distribution.  In particular:
00019  *
00020  * - The above copyright notice and this permission notice must appear
00021  * in all copies of the software and related documentation.
00022  *
00023  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00024  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00025  * 
00026  * <hr>
00027  *
00028  */
00029 /*****************************************************************************/
00030 
00031 #ifdef RATIONAL_GMP
00032 
00033 #include "compat_hash_set.h"
00034 #include "rational.h"
00035 
00036 #include <sstream>
00037 #include <gmp.h>
00038 
00039 namespace CVCL {
00040 
00041   using namespace std;
00042 
00043   //! Implementation of the forward-declared internal class
00044   class Rational::Impl {
00045     mpq_t d_n;
00046     //! Make the rational number canonical
00047     void canonicalize() { mpq_canonicalize(d_n); }
00048   public:
00049     //! Default Constructor
00050     Impl() { mpq_init(d_n); }
00051     //! Copy constructor (assumes x is canonicalized)
00052     Impl(const Impl &x) { mpq_init(d_n); mpq_set(d_n, x.d_n); }
00053     //! Constructor from mpq_t
00054     Impl(mpq_t n) {
00055       mpq_init(d_n);
00056       mpq_set(d_n, n);
00057       canonicalize();
00058     }
00059     //! Constructor from a pair of mpz_t (integers)
00060     Impl(mpz_t n, mpz_t d) {
00061       mpq_init(d_n);
00062       mpq_set_num(d_n, n); mpq_set_den(d_n, d);
00063       canonicalize();
00064     }
00065     //! Constructor from a single mpz_t (integer)
00066     Impl(mpz_t n) {
00067       mpq_init(d_n);
00068       mpq_set_num(d_n, n);
00069       canonicalize();
00070     }
00071     //! Constructor from a pair of integers
00072     Impl(long int n, long int d);
00073     //! Constructor from a pair of unsigned integers
00074     Impl(unsigned int n, unsigned int d, unsigned int /* dummy arg */);
00075     //! Constructor from a string
00076     Impl(const string &n, int base);
00077     //! Constructor from a pair of strings
00078     Impl(const string &n, const string& d, int base);
00079     // Destructor
00080     virtual ~Impl() { mpq_clear(d_n); }
00081 
00082     //! Assignment
00083     Impl& operator=(const Impl& x) {
00084       if(this == &x) return *this;
00085       mpq_set(d_n, x.d_n);
00086       return *this;
00087     }
00088     
00089     //! Get numerator
00090     Impl getNum() const {
00091       return Impl(mpq_numref(const_cast<Impl*>(this)->d_n));
00092     }
00093     //! Get denominator
00094     Impl getDen() const {
00095       return Impl(mpq_denref(const_cast<Impl*>(this)->d_n));
00096     }
00097 
00098     int getInt() const {
00099       // Check for overflow
00100       static Impl min((int)INT_MIN, 1), max((int)INT_MAX, 1);
00101       FatalAssert(isInteger() && min <= *this && *this <= max,
00102                   "Rational::getInt(): Arithmetic overflow for "
00103                   +toString());
00104       return mpz_get_si(mpq_numref(d_n));
00105     }
00106 
00107     unsigned int getUnsigned() const {
00108       // Check for overflow
00109       static Impl min(0, 1, 0), max(UINT_MAX, 1, 0);
00110       FatalAssert(min <= *this && *this <= max,
00111                   "Rational::getUnsigned(): Arithmetic overflow for "
00112                   +toString());
00113       return mpz_get_ui(mpq_numref(d_n));
00114     }
00115 
00116     //! Unary minus
00117     Impl operator-() const;
00118     //! Get the floor
00119     Impl floor() const;
00120     //! Get the ceiling
00121     Impl ceil() const;
00122 
00123     //! Testing whether the denominator is 1
00124     bool isInteger() const;
00125 
00126     //! Equality
00127     friend bool operator==(const Impl& x, const Impl& y) {
00128       return mpq_equal(x.d_n, y.d_n);
00129     }
00130 
00131     //! Dis-equality
00132     friend bool operator!=(const Impl& x, const Impl& y) {
00133       return !mpq_equal(x.d_n, y.d_n);
00134     }
00135     //! Less than
00136     friend bool operator<(const Impl& x, const Impl& y) {
00137       return mpq_cmp(x.d_n, y.d_n) < 0;
00138     }
00139 
00140     friend bool operator<=(const Impl& x, const Impl& y) {
00141       return mpq_cmp(x.d_n, y.d_n) <= 0;
00142     }
00143 
00144     friend bool operator>(const Impl& x, const Impl& y) {
00145       return mpq_cmp(x.d_n, y.d_n) > 0;
00146     }
00147 
00148     friend bool operator>=(const Impl& x, const Impl& y) {
00149       return mpq_cmp(x.d_n, y.d_n) >= 0;
00150     }
00151 
00152     //! Addition
00153     friend Impl operator+(const Impl& x, const Impl& y) {
00154       Impl res;
00155       mpq_add(res.d_n, x.d_n, y.d_n);
00156       return res;
00157     }
00158 
00159     //! Subtraction
00160     friend Impl operator-(const Impl& x, const Impl& y) {
00161       Impl res;
00162       mpq_sub(res.d_n, x.d_n, y.d_n);
00163       return res;
00164     }
00165 
00166     //! Multiplication
00167     friend Impl operator*(const Impl& x, const Impl& y) {
00168       Impl res;
00169       mpq_mul(res.d_n, x.d_n, y.d_n);
00170       return res;
00171     }
00172 
00173     //! Division
00174     friend Impl operator/(const Impl& x, const Impl& y) {
00175       Impl res;
00176       mpq_div(res.d_n, x.d_n, y.d_n);
00177       return res;
00178     }
00179 
00180     friend Impl operator%(const Impl& x, const Impl& y) {
00181       DebugAssert(x.isInteger() && y.isInteger(),
00182                   "Impl % Impl: x and y must be integers");
00183       mpz_t res;
00184       mpz_init(res);
00185       // Put the remainder directly into 'res'
00186       mpz_fdiv_r(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
00187       Impl r(res);
00188       mpz_clear(res);
00189       return r;
00190     }
00191 
00192     //! Compute the remainder of x/y
00193     friend Impl mod(const Impl& x, const Impl& y) {
00194       DebugAssert(x.isInteger() && y.isInteger(),
00195                   "Rational::Impl::mod(): x="+x.toString()
00196                   +", y="+y.toString());
00197       mpz_t res;
00198       mpz_init(res);
00199       mpz_mod(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
00200       Impl r(res);
00201       mpz_clear(res);
00202       return r;
00203     }
00204 
00205     friend Impl gcd(const Impl& x, const Impl& y) {
00206       DebugAssert(x.isInteger() && y.isInteger(),
00207                   "Rational::Impl::gcd(): x="+x.toString()
00208                   +", y="+y.toString());
00209       TRACE("rational", "Impl::gcd(", x, ", "+y.toString()+") {");
00210       mpz_t res;
00211       mpz_init(res);
00212       mpz_gcd(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
00213       Impl r(res);
00214       mpz_clear(res);
00215       TRACE("rational", "Impl::gcd => ", r, "}");
00216       return r;
00217     }
00218 
00219     friend Impl lcm(const Impl& x, const Impl& y) {
00220       DebugAssert(x.isInteger() && y.isInteger(),
00221                   "Rational::Impl::lcm(): x="+x.toString()
00222                   +", y="+y.toString());
00223       mpz_t res;
00224       mpz_init(res);
00225       mpz_lcm(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
00226       Impl r(res);
00227       mpz_clear(res);
00228       return r;
00229     }
00230 
00231     //! Print to string
00232     string toString(int base = 10) const {
00233       char* str = (char*)malloc(mpz_sizeinbase(mpq_numref(d_n), base)
00234                                 +mpz_sizeinbase(mpq_denref(d_n), base)+3);
00235       mpq_get_str(str, base, d_n);
00236       string res(str);
00237       free(str);
00238       return res;
00239     }
00240 
00241     //! Printing to ostream
00242     friend ostream& operator<<(ostream& os, const Rational::Impl& n) {
00243       return os << n.toString();
00244     }
00245       
00246   };
00247 
00248   // Constructor from a pair of integers
00249   Rational::Impl::Impl(long int n, long int d) {
00250     mpq_init(d_n);
00251     DebugAssert(d > 0, "Rational::Impl(long n, long d): d = "+int2string(d));
00252     mpq_set_si(d_n, n, (unsigned long int)d);
00253     canonicalize();
00254   }
00255 
00256   // Constructor from a pair of unsigned integers
00257   Rational::Impl::Impl(unsigned int n, unsigned int d,
00258                        unsigned int /* dummy arg, to disambiguate */) {
00259     mpq_init(d_n);
00260     mpq_set_ui(d_n, n, (unsigned long int)d);
00261     canonicalize();
00262   }
00263 
00264   // Constructor from a string
00265   Rational::Impl::Impl(const string &n, int base) {
00266     mpq_init(d_n);
00267     mpq_set_str(d_n, n.c_str(), base);
00268     canonicalize();
00269   }
00270 
00271   // Constructor from a pair of strings
00272   Rational::Impl::Impl(const string &n, const string& d, int base) {
00273     mpq_init(d_n);
00274     mpq_set_str(d_n, (n+"/"+d).c_str(), base);
00275     canonicalize();
00276   }
00277 
00278   Rational::Impl Rational::Impl::operator-() const {
00279     Impl res;
00280     mpq_neg(res.d_n, d_n);
00281     return res;
00282   }
00283 
00284   Rational::Impl Rational::Impl::floor() const {
00285     mpz_t res;
00286     mpz_init(res);
00287     mpz_fdiv_q(res, mpq_numref(d_n), mpq_denref(d_n));
00288     Impl r(res);
00289     mpz_clear(res);
00290     return r;
00291   }
00292 
00293   Rational::Impl Rational::Impl::ceil() const {
00294     mpz_t res;
00295     mpz_init(res);
00296     mpz_cdiv_q(res, mpq_numref(d_n), mpq_denref(d_n));
00297     Impl r(res);
00298     mpz_clear(res);
00299     return r;
00300   }
00301 
00302   bool Rational::Impl::isInteger() const {
00303     bool res(mpz_cmp_ui(mpq_denref(d_n), 1) == 0);
00304     TRACE("rational", "Impl::isInteger(", *this,
00305           ") => "+string(res? "true" : "false"));
00306     return res;
00307   }
00308 
00309   //! Default constructor
00310   Rational::Rational() : d_n(new Impl) {
00311 #ifdef _DEBUG_RATIONAL_
00312     int &num_created = getCreated();
00313     num_created++;
00314     printStats();
00315 #endif
00316   }
00317   //! Copy constructor
00318   Rational::Rational(const Rational &n) : d_n(new Impl(*n.d_n)) {
00319 #ifdef _DEBUG_RATIONAL_
00320     int &num_created = getCreated();
00321     num_created++;
00322     printStats();
00323 #endif
00324   }
00325 
00326   //! Private constructor
00327   Rational::Rational(const Impl& t): d_n(new Impl(t)) {
00328 #ifdef _DEBUG_RATIONAL_
00329     int &num_created = getCreated();
00330     num_created++;
00331     printStats();
00332 #endif
00333   }
00334   Rational::Rational(int n, int d): d_n(new Impl(n, d)) {
00335 #ifdef _DEBUG_RATIONAL_
00336     int &num_created = getCreated();
00337     num_created++;
00338     printStats();
00339 #endif
00340   }
00341   // Constructors from strings
00342   Rational::Rational(const char* n, int base)
00343     : d_n(new Impl(string(n), base)) {
00344 #ifdef _DEBUG_RATIONAL_
00345     int &num_created = getCreated();
00346     num_created++;
00347     printStats();
00348 #endif
00349   }
00350   Rational::Rational(const string& n, int base)
00351     : d_n(new Impl(n, base)) {
00352 #ifdef _DEBUG_RATIONAL_
00353     int &num_created = getCreated();
00354     num_created++;
00355     printStats();
00356 #endif
00357   }
00358   Rational::Rational(const char* n, const char* d, int base)
00359     : d_n(new Impl(string(n), string(d), base)) {
00360 #ifdef _DEBUG_RATIONAL_
00361     int &num_created = getCreated();
00362     num_created++;
00363     printStats();
00364 #endif
00365   }
00366   Rational::Rational(const string& n, const string& d, int base)
00367     : d_n(new Impl(n, d, base)) {
00368 #ifdef _DEBUG_RATIONAL_
00369     int &num_created = getCreated();
00370     num_created++;
00371     printStats();
00372 #endif
00373   }
00374   // Destructor
00375   Rational::~Rational() {
00376     delete d_n;
00377 #ifdef _DEBUG_RATIONAL_
00378     int &num_deleted = getDeleted();
00379     num_deleted++;
00380     printStats();
00381 #endif
00382   }
00383 
00384   // Get components
00385   Rational Rational::getNumerator() const
00386     { return Rational(d_n->getNum()); }
00387   Rational Rational::getDenominator() const
00388     { return Rational(d_n->getDen()); }
00389 
00390   bool Rational::isInteger() const { return d_n->isInteger(); }
00391 
00392   // Assignment
00393   Rational& Rational::operator=(const Rational& n) {
00394     if(this == &n) return *this;
00395     delete d_n;
00396     d_n = new Impl(*n.d_n);
00397     return *this;
00398   }
00399 
00400   ostream &operator<<(ostream &os, const Rational &n) {
00401     return(os << n.toString());
00402   }
00403 
00404 
00405   // Check that argument is an int and print an error message otherwise
00406 
00407   static void checkInt(const Rational& n, const string& funName) {
00408     TRACE("rational", "checkInt(", n, ")");
00409     DebugAssert(n.isInteger(),
00410                 "CVCL::Rational::" + funName
00411                 + ": argument is not an integer: " + n.toString());
00412   }
00413 
00414     /* Computes gcd and lcm on *integer* values. Result is always a
00415        positive integer.  In this implementation, it is guaranteed by
00416        GMP. */
00417 
00418   Rational gcd(const Rational &x, const Rational &y) {
00419     checkInt(x, "gcd(*x*,y)");
00420     checkInt(y, "gcd(x,*y*)");
00421     return Rational(gcd(*x.d_n, *y.d_n));
00422   }
00423  
00424   Rational gcd(const vector<Rational> &v) {
00425     Rational::Impl g(1,1), zero;
00426     if(v.size() > 0) {
00427       checkInt(v[0], "gcd(vector<Rational>[0])");
00428       g = *v[0].d_n;
00429     }
00430     for(size_t i=1; i<v.size(); i++) {
00431       checkInt(v[i], "gcd(vector<Rational>)");
00432       if(g == zero)
00433         g = *(v[i].d_n);
00434       else if(*(v[i].d_n) != zero)
00435         g = gcd(g, *(v[i].d_n));
00436     }
00437     return Rational(g);
00438   }
00439 
00440   Rational lcm(const Rational &x, const Rational &y) {
00441     checkInt(x, "lcm(*x*,y)");
00442     checkInt(y, "lcm(x,*y*)");
00443     return Rational(lcm(*x.d_n, *y.d_n));
00444   }
00445 
00446   Rational lcm(const vector<Rational> &v) {
00447     Rational::Impl g(1,1), zero;
00448     for(size_t i=0; i<v.size(); i++) {
00449       checkInt(v[i], "lcm(vector<Rational>)");
00450       if(*v[i].d_n != zero)
00451         g = lcm(g, *v[i].d_n);
00452     }
00453     return Rational(g);
00454   }
00455 
00456   Rational abs(const Rational &x) {
00457     if(x<0) return -x;
00458     return x;
00459   }
00460 
00461   Rational floor(const Rational &x) {
00462     return Rational(x.d_n->floor());
00463   }
00464 
00465   Rational ceil(const Rational &x) {
00466     return Rational(x.d_n->ceil());
00467   }
00468 
00469   Rational mod(const Rational &x, const Rational &y) {
00470     checkInt(x, "mod(*x*,y)");
00471     checkInt(y, "mod(x,*y*)");
00472     return(Rational(mod(*x.d_n, *y.d_n)));
00473   }
00474   
00475   string Rational::toString(int base) const {
00476     return(d_n->toString(base));
00477   }
00478 
00479   size_t Rational::hash() const {
00480     std::hash<const char *> h;
00481     return h(toString().c_str());
00482   }
00483   
00484   void Rational::print() const {
00485     cout << (*this) << endl;
00486   }
00487 
00488   // Unary minus
00489   Rational Rational::operator-() const {
00490     return Rational(-(*d_n));
00491   }
00492   
00493   Rational &Rational::operator+=(const Rational &n2) {
00494     *this = (*this) + n2;
00495     return *this;
00496   }
00497   
00498   Rational &Rational::operator-=(const Rational &n2) {
00499     *this = (*this) - n2;
00500     return *this;
00501   }
00502   
00503   Rational &Rational::operator*=(const Rational &n2) {
00504     *this = (*this) * n2;
00505     return *this;
00506   }
00507   
00508   Rational &Rational::operator/=(const Rational &n2) {
00509     *this = (*this) / n2;
00510     return *this;
00511   }
00512 
00513   int Rational::getInt() const {
00514     checkInt(*this, "getInt()");
00515     return d_n->getInt();
00516   }
00517 
00518   unsigned int Rational::getUnsigned() const {
00519     checkInt(*this, "getUnsigned()");
00520     return d_n->getUnsigned();
00521   }
00522 
00523 #ifdef _DEBUG_RATIONAL_
00524   void Rational::printStats() {
00525       int &num_created = getCreated();
00526       int &num_deleted = getDeleted();
00527       if(num_created % 1000 == 0 || num_deleted % 1000 == 0) {
00528         std::cerr << "Rational(" << *d_n << "): created " << num_created
00529                   << ", deleted " << num_deleted
00530                   << ", currently alive " << num_created-num_deleted
00531                   << std::endl;
00532       }
00533     }
00534 #endif
00535 
00536     bool operator==(const Rational &n1, const Rational &n2) {
00537       return(*n1.d_n == *n2.d_n);
00538     }
00539 
00540     bool operator<(const Rational &n1, const Rational &n2) {
00541       return(*n1.d_n < *n2.d_n);
00542     }
00543 
00544     bool operator<=(const Rational &n1, const Rational &n2) {
00545       return(*n1.d_n <= *n2.d_n);
00546     }
00547 
00548     bool operator>(const Rational &n1, const Rational &n2) {
00549       return(*n1.d_n > *n2.d_n);
00550     }
00551 
00552     bool operator>=(const Rational &n1, const Rational &n2) {
00553       return(*n1.d_n >= *n2.d_n);
00554     }
00555 
00556     bool operator!=(const Rational &n1, const Rational &n2) {
00557       return(*n1.d_n != *n2.d_n);
00558     }
00559 
00560     Rational operator+(const Rational &n1, const Rational &n2) {
00561       return Rational((*n1.d_n) + (*n2.d_n));
00562     }
00563 
00564     Rational operator-(const Rational &n1, const Rational &n2) {
00565       return Rational((*n1.d_n) - (*n2.d_n));
00566     }
00567 
00568     Rational operator*(const Rational &n1, const Rational &n2) {
00569       return Rational((*n1.d_n) * (*n2.d_n));
00570     }
00571 
00572     Rational operator/(const Rational &n1, const Rational &n2) {
00573       return Rational((*n1.d_n) / (*n2.d_n));
00574     }
00575 
00576     Rational operator%(const Rational &n1, const Rational &n2) {
00577       return Rational((*n1.d_n) + (*n2.d_n));
00578     }
00579 
00580 }; /* close namespace */
00581 
00582 #endif

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