/*****************************************************************************/ /*! * \file rational.cpp * * Author: Sergey Berezin * * Created: Dec 12 22:00:18 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // Class: Rational // Author: Sergey Berezin, 12/12/2002 (adapted from Bignum) // // Description: Implementation of class Rational. See comments in // rational.h file. /////////////////////////////////////////////////////////////////////////////// #ifdef RATIONAL_GMPXX #include #include "compat_hash_set.h" #include "rational.h" namespace CVC3 { using namespace std; // Implementation of the forward-declared internal class class Rational::Impl : public mpq_class { public: // mpz_class _n; // Constructors Impl() : mpq_class() { } // Constructor from integer // Impl(const mpz_class &x) : mpq_class(x) { } // Constructor from rational Impl(const mpq_class &x) : mpq_class(x) { } // Copy constructor Impl(const Impl &x) : mpq_class(x) { } // From pair of integers / strings Impl(int n, int d) : mpq_class(n,d) { canonicalize(); } Impl(const mpz_class& n, const mpz_class& d) : mpq_class(n,d) { canonicalize(); } // From string(s) Impl(const string &n, int base): mpq_class(n, base) { canonicalize(); } Impl(const string &n, const string& d, int base) : mpq_class(n + "/" + d, base) { canonicalize(); } // Destructor virtual ~Impl() { } // Getting numerator and denominator. DON NOT ASSIGN to the result mpz_class getNum() { return get_num(); } mpz_class getDen() { return get_den(); } }; // Constructors Rational::Rational() : d_n(new Impl) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Copy constructor Rational::Rational(const Rational &n) : d_n(new Impl(*n.d_n)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Private constructor Rational::Rational(const Impl& t): d_n(new Impl(t)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(int n, int d): d_n(new Impl(n, d)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Constructors from strings Rational::Rational(const char* n, int base) : d_n(new Impl(string(n), base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const string& n, int base) : d_n(new Impl(n, base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const char* n, const char* d, int base) : d_n(new Impl(string(n), string(d), base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const string& n, const string& d, int base) : d_n(new Impl(n, d, base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Destructor Rational::~Rational() { delete d_n; #ifdef _DEBUG_RATIONAL_ int &num_deleted = getDeleted(); num_deleted++; printStats(); #endif } // Get components Rational Rational::getNumerator() const { return Rational(Impl(d_n->getNum(), 1)); } Rational Rational::getDenominator() const { return Rational(Impl(d_n->getDen(), 1)); } bool Rational::isInteger() const { return 1 == d_n->getDen(); } // Assignment Rational& Rational::operator=(const Rational& n) { if(this == &n) return *this; delete d_n; d_n = new Impl(*n.d_n); return *this; } ostream &operator<<(ostream &os, const Rational &n) { return(os << n.toString()); } // Check that argument is an int and print an error message otherwise static void checkInt(const Rational& n, const string& funName) { DebugAssert(n.isInteger(), ("CVC3::Rational::" + funName + ": argument is not an integer: " + n.toString()).c_str()); } /* Computes gcd and lcm on *integer* values. Result is always a positive integer. In this implementation, it is guaranteed by GMP. */ Rational gcd(const Rational &x, const Rational &y) { mpz_class g; checkInt(x, "gcd(*x*,y)"); checkInt(y, "gcd(x,*y*)"); mpz_gcd(g.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t()); return Rational(Rational::Impl(g,1)); } Rational gcd(const vector &v) { mpz_class g(1); if(v.size() > 0) { checkInt(v[0], "gcd(vector[0])"); g = v[0].d_n->getNum(); } for(unsigned i=1; i)"); if(*v[i].d_n != 0) mpz_gcd(g.get_mpz_t(), g.get_mpz_t(), v[i].d_n->get_num_mpz_t()); } return Rational(Rational::Impl(g,1)); } Rational lcm(const Rational &x, const Rational &y) { mpz_class g; checkInt(x, "lcm(*x*,y)"); checkInt(y, "lcm(x,*y*)"); mpz_lcm(g.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t()); return Rational(Rational::Impl(g, 1)); } Rational lcm(const vector &v) { mpz_class g(1); for(unsigned i=0; i)"); if(*v[i].d_n != 0) mpz_lcm(g.get_mpz_t(), g.get_mpz_t(), v[i].d_n->get_num_mpz_t()); } return Rational(Rational::Impl(g,1)); } Rational abs(const Rational &x) { return Rational(Rational::Impl(abs(*x.d_n))); } Rational floor(const Rational &x) { mpz_class q; mpz_fdiv_q(q.get_mpz_t(), x.d_n->get_num_mpz_t(), x.d_n->get_den_mpz_t()); return Rational(Rational::Impl(q,1)); } Rational ceil(const Rational &x) { mpz_class q; mpz_cdiv_q(q.get_mpz_t(), x.d_n->get_num_mpz_t(), x.d_n->get_den_mpz_t()); return Rational(Rational::Impl(q,1)); } Rational mod(const Rational &x, const Rational &y) { checkInt(x, "mod(*x*,y)"); checkInt(y, "mod(x,*y*)"); mpz_class r; mpz_mod(r.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t()); return(Rational(Rational::Impl(r,1))); } string Rational::toString(int base) const { char *tmp = mpq_get_str(NULL, base, d_n->get_mpq_t()); string res(tmp); // delete tmp; free(tmp); return(res); } size_t Rational::hash() const { std::hash h; return h(toString().c_str()); } void Rational::print() const { cout << (*d_n) << endl; } // Unary minus Rational Rational::operator-() const { return Rational(Rational::Impl(- (*d_n))); } Rational &Rational::operator+=(const Rational &n2) { *d_n += (*n2.d_n); return *this; } Rational &Rational::operator-=(const Rational &n2) { *d_n -= (*n2.d_n); return *this; } Rational &Rational::operator*=(const Rational &n2) { *d_n *= (*n2.d_n); return *this; } Rational &Rational::operator/=(const Rational &n2) { *d_n /= (*n2.d_n); return *this; } int Rational::getInt() const { checkInt(*this, "getInt()"); return mpz_get_si(d_n->get_num_mpz_t()); } unsigned int Rational::getUnsigned() const { checkInt(*this, "getUnsigned()"); return mpz_get_ui(d_n->get_num_mpz_t()); } #ifdef _DEBUG_RATIONAL_ void Rational::printStats() { int &num_created = getCreated(); int &num_deleted = getDeleted(); if(num_created % 1000 == 0 || num_deleted % 1000 == 0) { std::cerr << "Rational(" << *d_n << "): created " << num_created << ", deleted " << num_deleted << ", currently alive " << num_created-num_deleted << std::endl; } } #endif bool operator==(const Rational &n1, const Rational &n2) { return(*n1.d_n == *n2.d_n); } bool operator<(const Rational &n1, const Rational &n2) { return(*n1.d_n < *n2.d_n); } bool operator<=(const Rational &n1, const Rational &n2) { return(*n1.d_n <= *n2.d_n); } bool operator>(const Rational &n1, const Rational &n2) { return(*n1.d_n > *n2.d_n); } bool operator>=(const Rational &n1, const Rational &n2) { return(*n1.d_n >= *n2.d_n); } bool operator!=(const Rational &n1, const Rational &n2) { return(*n1.d_n != *n2.d_n); } Rational operator+(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n + *n2.d_n)); } Rational operator-(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl((*n1.d_n) - (*n2.d_n))); } Rational operator*(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl((*n1.d_n) * (*n2.d_n))); } Rational operator/(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n / *n2.d_n)); } Rational operator%(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n + *n2.d_n)); } }; /* close namespace */ #endif