/*****************************************************************************/
/*!
* \file rational-gmp.cpp
*
* \brief Implementation of class Rational using GMP library (C interface)
*
* Author: Sergey Berezin
*
* Created: Mon Aug 4 10:06:04 2003
*
*
* 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.
*
*
*
*/
/*****************************************************************************/
#ifdef RATIONAL_GMP
#include "compat_hash_set.h"
#include "rational.h"
#include
#include
namespace CVC3 {
using namespace std;
//! Implementation of the forward-declared internal class
class Rational::Impl {
mpq_t d_n;
//! Make the rational number canonical
void canonicalize() { mpq_canonicalize(d_n); }
public:
//! Default Constructor
Impl() { mpq_init(d_n); }
//! Copy constructor (assumes x is canonicalized)
Impl(const Impl &x) { mpq_init(d_n); mpq_set(d_n, x.d_n); }
//! Constructor from mpq_t
Impl(mpq_t n) {
mpq_init(d_n);
mpq_set(d_n, n);
canonicalize();
}
//! Constructor from a pair of mpz_t (integers)
Impl(mpz_t n, mpz_t d) {
mpq_init(d_n);
mpq_set_num(d_n, n); mpq_set_den(d_n, d);
canonicalize();
}
//! Constructor from a single mpz_t (integer)
Impl(mpz_t n) {
mpq_init(d_n);
mpq_set_num(d_n, n);
canonicalize();
}
//! Constructor from a pair of integers
Impl(long int n, long int d);
//! Constructor from a pair of unsigned integers
Impl(unsigned int n, unsigned int d, unsigned int /* dummy arg */);
//! Constructor from a string
Impl(const string &n, int base);
//! Constructor from a pair of strings
Impl(const string &n, const string& d, int base);
// Destructor
virtual ~Impl() { mpq_clear(d_n); }
//! Assignment
Impl& operator=(const Impl& x) {
if(this == &x) return *this;
mpq_set(d_n, x.d_n);
return *this;
}
//! Get numerator
Impl getNum() const {
return Impl(mpq_numref(const_cast(this)->d_n));
}
//! Get denominator
Impl getDen() const {
return Impl(mpq_denref(const_cast(this)->d_n));
}
int getInt() const {
// Check for overflow
static Impl min((int)INT_MIN, 1), max((int)INT_MAX, 1);
FatalAssert(isInteger() && min <= *this && *this <= max,
"Rational::getInt(): Arithmetic overflow for "
+toString());
return mpz_get_si(mpq_numref(d_n));
}
unsigned int getUnsigned() const {
// Check for overflow
static Impl min(0, 1, 0), max(UINT_MAX, 1, 0);
FatalAssert(min <= *this && *this <= max,
"Rational::getUnsigned(): Arithmetic overflow for "
+toString());
return mpz_get_ui(mpq_numref(d_n));
}
//! Unary minus
Impl operator-() const;
//! Get the floor
Impl floor() const;
//! Get the ceiling
Impl ceil() const;
//! Testing whether the denominator is 1
bool isInteger() const;
//! Equality
friend bool operator==(const Impl& x, const Impl& y) {
return mpq_equal(x.d_n, y.d_n);
}
//! Dis-equality
friend bool operator!=(const Impl& x, const Impl& y) {
return !mpq_equal(x.d_n, y.d_n);
}
//! Less than
friend bool operator<(const Impl& x, const Impl& y) {
return mpq_cmp(x.d_n, y.d_n) < 0;
}
friend bool operator<=(const Impl& x, const Impl& y) {
return mpq_cmp(x.d_n, y.d_n) <= 0;
}
friend bool operator>(const Impl& x, const Impl& y) {
return mpq_cmp(x.d_n, y.d_n) > 0;
}
friend bool operator>=(const Impl& x, const Impl& y) {
return mpq_cmp(x.d_n, y.d_n) >= 0;
}
//! Addition
friend Impl operator+(const Impl& x, const Impl& y) {
Impl res;
mpq_add(res.d_n, x.d_n, y.d_n);
return res;
}
//! Subtraction
friend Impl operator-(const Impl& x, const Impl& y) {
Impl res;
mpq_sub(res.d_n, x.d_n, y.d_n);
return res;
}
//! Multiplication
friend Impl operator*(const Impl& x, const Impl& y) {
Impl res;
mpq_mul(res.d_n, x.d_n, y.d_n);
return res;
}
//! Division
friend Impl operator/(const Impl& x, const Impl& y) {
Impl res;
mpq_div(res.d_n, x.d_n, y.d_n);
return res;
}
friend Impl operator%(const Impl& x, const Impl& y) {
DebugAssert(x.isInteger() && y.isInteger(),
"Impl % Impl: x and y must be integers");
mpz_t res;
mpz_init(res);
// Put the remainder directly into 'res'
mpz_fdiv_r(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
Impl r(res);
mpz_clear(res);
return r;
}
//! Compute the remainder of x/y
friend Impl mod(const Impl& x, const Impl& y) {
DebugAssert(x.isInteger() && y.isInteger(),
"Rational::Impl::mod(): x="+x.toString()
+", y="+y.toString());
mpz_t res;
mpz_init(res);
mpz_mod(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
Impl r(res);
mpz_clear(res);
return r;
}
friend Impl gcd(const Impl& x, const Impl& y) {
DebugAssert(x.isInteger() && y.isInteger(),
"Rational::Impl::gcd(): x="+x.toString()
+", y="+y.toString());
TRACE("rational", "Impl::gcd(", x, ", "+y.toString()+") {");
mpz_t res;
mpz_init(res);
mpz_gcd(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
Impl r(res);
mpz_clear(res);
TRACE("rational", "Impl::gcd => ", r, "}");
return r;
}
friend Impl lcm(const Impl& x, const Impl& y) {
DebugAssert(x.isInteger() && y.isInteger(),
"Rational::Impl::lcm(): x="+x.toString()
+", y="+y.toString());
mpz_t res;
mpz_init(res);
mpz_lcm(res, mpq_numref(x.d_n), mpq_numref(y.d_n));
Impl r(res);
mpz_clear(res);
return r;
}
//! Print to string
string toString(int base = 10) const {
char* str = (char*)malloc(mpz_sizeinbase(mpq_numref(d_n), base)
+mpz_sizeinbase(mpq_denref(d_n), base)+3);
mpq_get_str(str, base, d_n);
string res(str);
free(str);
return res;
}
//! Printing to ostream
friend ostream& operator<<(ostream& os, const Rational::Impl& n) {
return os << n.toString();
}
};
// Constructor from a pair of integers
Rational::Impl::Impl(long int n, long int d) {
mpq_init(d_n);
DebugAssert(d > 0, "Rational::Impl(long n, long d): d = "+int2string(d));
mpq_set_si(d_n, n, (unsigned long int)d);
canonicalize();
}
// Constructor from a pair of unsigned integers
Rational::Impl::Impl(unsigned int n, unsigned int d,
unsigned int /* dummy arg, to disambiguate */) {
mpq_init(d_n);
mpq_set_ui(d_n, n, (unsigned long int)d);
canonicalize();
}
// Constructor from a string
Rational::Impl::Impl(const string &n, int base) {
mpq_init(d_n);
mpq_set_str(d_n, n.c_str(), base);
canonicalize();
}
// Constructor from a pair of strings
Rational::Impl::Impl(const string &n, const string& d, int base) {
mpq_init(d_n);
mpq_set_str(d_n, (n+"/"+d).c_str(), base);
canonicalize();
}
Rational::Impl Rational::Impl::operator-() const {
Impl res;
mpq_neg(res.d_n, d_n);
return res;
}
Rational::Impl Rational::Impl::floor() const {
mpz_t res;
mpz_init(res);
mpz_fdiv_q(res, mpq_numref(d_n), mpq_denref(d_n));
Impl r(res);
mpz_clear(res);
return r;
}
Rational::Impl Rational::Impl::ceil() const {
mpz_t res;
mpz_init(res);
mpz_cdiv_q(res, mpq_numref(d_n), mpq_denref(d_n));
Impl r(res);
mpz_clear(res);
return r;
}
bool Rational::Impl::isInteger() const {
bool res(mpz_cmp_ui(mpq_denref(d_n), 1) == 0);
TRACE("rational", "Impl::isInteger(", *this,
") => "+string(res? "true" : "false"));
return res;
}
//! Default constructor
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(d_n->getNum()); }
Rational Rational::getDenominator() const
{ return Rational(d_n->getDen()); }
bool Rational::isInteger() const { return d_n->isInteger(); }
// 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) {
TRACE("rational", "checkInt(", n, ")");
DebugAssert(n.isInteger(),
"CVC3::Rational::" + funName
+ ": argument is not an integer: " + n.toString());
}
/* 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) {
checkInt(x, "gcd(*x*,y)");
checkInt(y, "gcd(x,*y*)");
return Rational(gcd(*x.d_n, *y.d_n));
}
Rational gcd(const vector &v) {
Rational::Impl g(1,1), zero;
if(v.size() > 0) {
checkInt(v[0], "gcd(vector[0])");
g = *v[0].d_n;
}
for(size_t i=1; i)");
if(g == zero)
g = *(v[i].d_n);
else if(*(v[i].d_n) != zero)
g = gcd(g, *(v[i].d_n));
}
return Rational(g);
}
Rational lcm(const Rational &x, const Rational &y) {
checkInt(x, "lcm(*x*,y)");
checkInt(y, "lcm(x,*y*)");
return Rational(lcm(*x.d_n, *y.d_n));
}
Rational lcm(const vector &v) {
Rational::Impl g(1,1), zero;
for(size_t i=0; i)");
if(*v[i].d_n != zero)
g = lcm(g, *v[i].d_n);
}
return Rational(g);
}
Rational abs(const Rational &x) {
if(x<0) return -x;
return x;
}
Rational floor(const Rational &x) {
return Rational(x.d_n->floor());
}
Rational ceil(const Rational &x) {
return Rational(x.d_n->ceil());
}
Rational mod(const Rational &x, const Rational &y) {
checkInt(x, "mod(*x*,y)");
checkInt(y, "mod(x,*y*)");
return(Rational(mod(*x.d_n, *y.d_n)));
}
string Rational::toString(int base) const {
return(d_n->toString(base));
}
size_t Rational::hash() const {
std::hash h;
return h(toString().c_str());
}
void Rational::print() const {
cout << (*this) << endl;
}
// Unary minus
Rational Rational::operator-() const {
return Rational(-(*d_n));
}
Rational &Rational::operator+=(const Rational &n2) {
*this = (*this) + n2;
return *this;
}
Rational &Rational::operator-=(const Rational &n2) {
*this = (*this) - n2;
return *this;
}
Rational &Rational::operator*=(const Rational &n2) {
*this = (*this) * n2;
return *this;
}
Rational &Rational::operator/=(const Rational &n2) {
*this = (*this) / n2;
return *this;
}
int Rational::getInt() const {
checkInt(*this, "getInt()");
return d_n->getInt();
}
unsigned int Rational::getUnsigned() const {
checkInt(*this, "getUnsigned()");
return d_n->getUnsigned();
}
#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((*n1.d_n) + (*n2.d_n));
}
Rational operator-(const Rational &n1, const Rational &n2) {
return Rational((*n1.d_n) - (*n2.d_n));
}
Rational operator*(const Rational &n1, const Rational &n2) {
return Rational((*n1.d_n) * (*n2.d_n));
}
Rational operator/(const Rational &n1, const Rational &n2) {
return Rational((*n1.d_n) / (*n2.d_n));
}
Rational operator%(const Rational &n1, const Rational &n2) {
return Rational((*n1.d_n) + (*n2.d_n));
}
}; /* close namespace */
#endif