/* Copyright (c) 1997-2007 Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany) http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version: http://www.gnu.org/licenses/gpl.txt. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #ifndef _POLYMAKE_GMP_RATIONAL_H #define _POLYMAKE_GMP_RATIONAL_H "$Project: polymake $$Id: Rational.h 7565 2007-01-16 16:29:43Z gawrilow $" #include <Integer.h> #include <string.h> #if __GNU_MP_VERSION < 4 #define _tmp_little_Integer(x) \ mpz_t x; \ mp_limb_t x##_limb; \ x[0]._mp_alloc=1; \ x[0]._mp_d=&x##_limb #endif class temp_Rational : public MP_RAT { protected: /// never instantiate this class: it is a pure masquerade temp_Rational(); ~temp_Rational(); }; Rational inv(const Rational& a); /** Arbitrary precision rational number. It is a wrapper around GMP (GNU Multiple Precision Library) type \\mpq_t\\. Developed and tested with GMP Version 3.1 and higher. See the GMP Home Pages at `http://www.swox.com/gmp/'. @index main */ class Rational { private: /// GMP's representation mpq_t rep; static void zero_division() __attribute__((noreturn)); void canonicalize() { if (!mpz_sgn(mpq_denref(rep))) zero_division(); mpq_canonicalize(rep); } public: #if defined(__GMP_PLUSPLUS__) //constructs from gmp's mpz_class as numerator and denominator Rational(const mpz_class& num, const mpz_class& den) { mpz_init_set(mpq_numref(rep), num.get_mpz_t()); mpz_init_set(mpq_denref(rep), den.get_mpz_t()); canonicalize(); } #endif /// Initializes to 0. Rational() { mpq_init(rep); } Rational(const Rational& a) { mpz_init_set(mpq_numref(rep), mpq_numref(a.rep)); mpz_init_set(mpq_denref(rep), mpq_denref(a.rep)); } Rational(const Integer& num) { mpz_init_set(mpq_numref(rep), num.rep); mpz_init_set_ui(mpq_denref(rep), 1); } Rational(long num) { mpz_init_set_si(mpq_numref(rep), num); mpz_init_set_ui(mpq_denref(rep), 1); } Rational(int num) { mpz_init_set_si(mpq_numref(rep), num); mpz_init_set_ui(mpq_denref(rep), 1); } Rational(const Integer& num, const Integer& den) { mpz_init_set(mpq_numref(rep), num.rep); mpz_init_set(mpq_denref(rep), den.rep); canonicalize(); } Rational(long num, long den) { mpz_init_set_si(mpq_numref(rep), num); mpz_init_set_si(mpq_denref(rep), den); canonicalize(); } Rational(const Integer& num, long den) { mpz_init_set(mpq_numref(rep), num.rep); mpz_init_set_si(mpq_denref(rep), den); canonicalize(); } Rational(long num, const Integer& den) { mpz_init_set_si(mpq_numref(rep), num); mpz_init_set(mpq_denref(rep), den.rep); canonicalize(); } Rational(const double& b) { mpq_init(rep); mpq_set_d(rep,b); } explicit Rational(const char* s) { mpq_init(rep); try { set(s); } catch (const gmp_error&) { mpq_clear(rep); throw; } } explicit Rational(mpq_srcptr src) { mpz_init_set(mpq_numref(rep), mpq_numref(src)); mpz_init_set(mpq_denref(rep), mpq_denref(src)); canonicalize(); } explicit Rational(mpz_srcptr num_src) { mpz_init_set(mpq_numref(rep), num_src); mpz_init_set_ui(mpq_denref(rep), 1); } Rational(mpz_srcptr num_src, mpz_srcptr den_src) { mpz_init_set(mpq_numref(rep), num_src); mpz_init_set(mpq_denref(rep), den_src); canonicalize(); } explicit Rational(temp_Rational& tmp) { rep[0]=tmp; canonicalize(); } explicit Rational(temp_Integer& tmp_num) { *mpq_numref(rep)=tmp_num; mpz_init_set_ui(mpq_denref(rep), 1); } Rational(temp_Integer& tmp_num, temp_Integer& tmp_den) { *mpq_numref(rep)=tmp_num; *mpq_denref(rep)=tmp_den; canonicalize(); } Rational(void (*f)(mpq_ptr,mpq_srcptr), mpq_srcptr a) { mpq_init(rep); f(rep,a); } template <class Arg> Rational(void (*f)(mpq_ptr,mpq_srcptr,Arg), mpq_srcptr a, Arg b) { mpq_init(rep); f(rep,a,b); } template <class Arg> Rational(void (*numf)(mpz_ptr,Arg), Arg a, mpz_srcptr den) { mpz_init(mpq_numref(rep)); numf(mpq_numref(rep),a); mpz_init_set(mpq_denref(rep),den); } template <class Arg> Rational(mpz_srcptr num, void (*denf)(mpz_ptr,Arg), Arg a) { mpz_init_set(mpq_numref(rep),num); mpz_init(mpq_denref(rep)); denf(mpq_denref(rep),a); } template <class Arg1, class Arg2> Rational(void (*numf)(mpz_ptr,Arg1,Arg2), Arg1 a, Arg2 b, mpz_srcptr den) { mpz_init(mpq_numref(rep)); numf(mpq_numref(rep),a,b); mpz_init_set(mpq_denref(rep),den); } template <class Arg1, class Arg2> Rational(mpz_srcptr num, void (*denf)(mpz_ptr,Arg1,Arg2), Arg1 a, Arg2 b) { mpz_init_set(mpq_numref(rep),num); mpz_init(mpq_denref(rep)); denf(mpq_denref(rep),a,b); } template <class Arg1, class Arg2> Rational(void (*numf)(mpz_ptr,Arg1,Arg2), Arg1 a, Arg2 b, unsigned long den) { mpz_init(mpq_numref(rep)); numf(mpq_numref(rep),a,b); mpz_init_set_ui(mpq_denref(rep),den); } template <class Arg1, class Arg2> Rational(unsigned long num, void (*denf)(mpz_ptr,Arg1,Arg2), Arg1 a, Arg2 b) { mpz_init_set_ui(mpq_numref(rep),num); mpz_init(mpq_denref(rep)); denf(mpq_denref(rep),a,b); } template <class Arg1, class Arg2> Rational(void (*numf)(mpz_ptr,Arg1,Arg2), mpz_srcptr num, Arg1 a, Arg2 b, mpz_srcptr den) { mpz_init_set(mpq_numref(rep),num); numf(mpq_numref(rep),a,b); mpz_init_set(mpq_denref(rep),den); } template <class Arg1, class Arg2> Rational(mpz_srcptr num, void (*denf)(mpz_ptr,Arg1,Arg2), Arg1 a, Arg2 b, mpz_srcptr den) { mpz_init_set(mpq_numref(rep),num); mpz_init_set(mpq_denref(rep),den); denf(mpq_denref(rep),a,b); } template <class Arg1, class Arg2, class Arg3, class Arg4> Rational(void (*numf)(mpz_ptr,Arg1,Arg2), Arg1 a, Arg2 b, void (*denf)(mpz_ptr,Arg3,Arg4), Arg3 c, Arg4 d) { mpq_init(rep); numf(mpq_numref(rep),a,b); denf(mpq_denref(rep),c,d); } friend Integer::Integer(const Rational& r); friend Integer& Integer::operator= (const Rational& r); ~Rational() { mpq_clear(rep); } protected: enum proxy_kind { num, den }; template <proxy_kind kind, bool _canonicalize=true> class proxy : public Integer { private: void canonicalize() { if (!_canonicalize) return; // The constant 8 is arbitrarily chosen. // Every non-zero double word aligned address would do as well. enum { fict_addr=8 }; reinterpret_cast<Rational*> (// address of the num/den field reinterpret_cast<char*>(this) - (// offset from the begin of a mpq_t to appropriate mpz_t reinterpret_cast<char*>(kind==num ? mpq_numref(reinterpret_cast<Rational*>(fict_addr)->rep) : mpq_denref(reinterpret_cast<Rational*>(fict_addr)->rep)) -reinterpret_cast<char*>(fict_addr))) ->canonicalize(); } /// both undefined proxy(const proxy&); proxy(); friend class Rational; public: template <class T> proxy& operator= (const T& b) { Integer::operator=(b); canonicalize(); return *this; } proxy& operator++() { Integer::operator++(); canonicalize(); return *this; } proxy& operator--() { Integer::operator--(); canonicalize(); return *this; } template <class T> proxy& operator+= (const T& b) { Integer::operator+=(b); canonicalize(); return *this; } template <class T> proxy& operator-= (const T& b) { Integer::operator-=(b); canonicalize(); return *this; } template <class T> proxy& operator*= (const T& b) { Integer::operator*=(b); canonicalize(); return *this; } template <class T> proxy& operator/= (const T& b) { Integer::operator/=(b); canonicalize(); return *this; } template <class T> proxy& operator%= (const T& b) { Integer::operator%=(b); canonicalize(); return *this; } template <class T> proxy& operator<<= (const T& b) { Integer::operator<<=(b); canonicalize(); return *this; } template <class T> proxy& operator>>= (const T& b) { Integer::operator>>=(b); canonicalize(); return *this; } }; public: friend const proxy<num>& numerator(const Rational& a) { return *reinterpret_cast<const proxy<num>*>(mpq_numref(a.rep)); } friend proxy<num>& numerator(Rational& a) { return *reinterpret_cast<proxy<num>*>(mpq_numref(a.rep)); } friend const proxy<den>& denominator(const Rational& a) { return *reinterpret_cast<const proxy<den>*>(mpq_denref(a.rep)); } friend proxy<den>& denominator(Rational& a) { return *reinterpret_cast<proxy<den>*>(mpq_denref(a.rep)); } friend proxy<num,false>& numerator_nocanon(Rational& a) { return *reinterpret_cast<proxy<num,false>*>(mpq_numref(a.rep)); } void set(const Integer& num, const Integer& den) { set(num.rep, den.rep); } void set(long num, long den) { mpz_set_si(mpq_numref(rep),num); mpz_set_si(mpq_denref(rep),den); canonicalize(); } /** Conversion from a printable representation. Numerator and denominator are expected delimited by `/'. Omitted denominator assumed equal to 1. */ Rational& set(const char *s) throw(gmp_error); Rational& operator= (const Rational& b) { mpq_set(rep, b.rep); return *this; } /// for the seldom case of unwrapped GMP objects coexisting with us Rational& set(mpz_srcptr num_src, mpz_srcptr den_src) { mpq_set_num(rep, num_src); mpq_set_den(rep, den_src); canonicalize(); return *this; } Rational& set(mpq_srcptr src) { mpq_set(rep, src); return *this; } Rational& operator= (const Integer& b) { mpq_set_z(rep, b.rep); return *this; } Rational& operator= (long b) { mpq_set_si(rep, b, 1); return *this; } Rational& operator= (int b) { return operator=(long(b)); } Rational& operator= (const double& b) { mpq_set_d(rep, b); return *this; } operator double() const { return mpq_get_d(rep); } operator long() const { return static_cast<Integer>(*this); } operator int() const { return static_cast<Integer>(*this); } /// Convert rational to string. std::string to_string(int base=10) const; /// Swaps the values. void swap(Rational& b) { mpq_swap(rep, b.rep); } /** Accelerated combination of copy constructor and destructor. Aimed to be used in container classes only! */ friend void relocate(Rational* from, Rational* to) { to->rep[0] = from->rep[0]; } /// Comparison with 0. bool operator!() const { return !mpq_sgn(rep); } /// Comparison with 0. operator bool() const { return mpq_sgn(rep); } Rational& operator++ () { mpz_add(mpq_numref(rep), mpq_numref(rep), mpq_denref(rep)); return *this; } Rational& operator-- () { mpz_sub(mpq_numref(rep), mpq_numref(rep), mpq_denref(rep)); return *this; } /// In-place negation. Rational& negate() { mpq_neg(rep, rep); return *this; } Rational& operator+= (const Rational& b) { mpq_add(rep, rep, b.rep); return *this; } Rational& operator+= (const Integer& b) { #if __GNU_MP_VERSION >= 4 mpz_addmul(mpq_numref(rep), mpq_denref(rep), b.rep); #else Integer t=denominator(*this)*b; mpz_add(mpq_numref(rep), mpq_numref(rep), t.rep); #endif return *this; } Rational& operator+= (long b) { #if __GNU_MP_VERSION >= 4 if (b>=0) mpz_addmul_ui(mpq_numref(rep), mpq_denref(rep), b); else mpz_submul_ui(mpq_numref(rep), mpq_denref(rep), -b); #else if (b) { mpz_t minus_den; mpz_srcptr den= b>0 ? mpq_denref(rep) : (b=-b, Integer::_tmp_negate(minus_den,mpq_denref(rep))); mpz_addmul_ui(mpq_numref(rep), den, b); } #endif return *this; } Rational& operator-= (const Rational& b) { mpq_sub(rep, rep, b.rep); return *this; } Rational& operator-= (const Integer& b) { #if __GNU_MP_VERSION >= 4 mpz_submul(mpq_numref(rep), mpq_denref(rep), b.rep); #else Integer t=denominator(*this)*b; mpz_sub(mpq_numref(rep), mpq_numref(rep), t.rep); #endif return *this; } Rational& operator-= (long b) { #if __GNU_MP_VERSION >= 4 if (b>=0) mpz_submul_ui(mpq_numref(rep), mpq_denref(rep), b); else mpz_addmul_ui(mpq_numref(rep), mpq_denref(rep), -b); #else if (b) { mpz_t minus_den; mpz_srcptr den= b>0 ? Integer::_tmp_negate(minus_den,mpq_denref(rep)) : (b=-b, mpq_denref(rep)); mpz_addmul_ui(mpq_numref(rep), den, b); } #endif return *this; } Rational& operator*= (const Rational& b) { mpq_mul(rep, rep, b.rep); return *this; } Rational& operator*= (const Integer& b); Rational& operator*= (long b) { if (!*this) return *this; if (b) { #if __GNU_MP_VERSION >= 4 unsigned long g=mpz_gcd_ui(0, mpq_denref(rep), b>=0 ? b : -b); if (g==1) { mpz_mul_si(mpq_numref(rep), mpq_numref(rep), b); } else { mpz_mul_si(mpq_numref(rep), mpq_numref(rep), b/g); mpz_divexact_ui(mpq_denref(rep), mpq_denref(rep), g); } #else _tmp_little_Integer(g); if (mpz_gcd_ui(g, mpq_denref(rep), b>=0 ? b : -b) == 1) { mpz_mul_si(mpq_numref(rep), mpq_numref(rep), b); } else { mpz_mul_si(mpq_numref(rep), mpq_numref(rep), b/g_limb); mpz_divexact(mpq_denref(rep), mpq_denref(rep), g); } #endif } else { *this=0; } return *this; } Rational& operator/= (const Rational& b) { mpq_div(rep, rep, b.rep); return *this; } Rational& operator/= (const Integer& b); Rational& operator/= (long b) { if (!b) zero_division(); if (*this) { const long babs=b>0 ? b : -b; #if __GNU_MP_VERSION >= 4 unsigned long g=mpz_gcd_ui(0, mpq_numref(rep), babs); if (g==1) { mpz_mul_ui(mpq_denref(rep), mpq_denref(rep), babs); } else { mpz_mul_ui(mpq_denref(rep), mpq_denref(rep), babs/g); mpz_divexact_ui(mpq_numref(rep), mpq_numref(rep), g); } #else _tmp_little_Integer(g); if (mpz_gcd_ui(g, mpq_numref(rep), babs) == 1) { mpz_mul_ui(mpq_denref(rep), mpq_denref(rep), babs); } else { mpz_mul_ui(mpq_denref(rep), mpq_denref(rep), babs/g_limb); mpz_divexact(mpq_numref(rep), mpq_numref(rep), g); } #endif if (b<0) mpz_neg(mpq_numref(rep), mpq_numref(rep)); } return *this; } /// Multiply with $2^k$. Rational& operator<<= (unsigned long k) { #if __GNU_MP_VERSION >= 4 mpq_mul_2exp(rep, rep, k); #else if (mpq_sgn(rep)) { unsigned long den0s=mpz_scan1(mpq_denref(rep), 0); if (k<=den0s) { mpz_tdiv_q_2exp(mpq_denref(rep), mpq_denref(rep), k); } else { mpz_tdiv_q_2exp(mpq_denref(rep), mpq_denref(rep), den0s); mpz_mul_2exp(mpq_numref(rep), mpq_numref(rep), k-den0s); } } #endif return *this; } /// Divide thru $2^k$. Rational& operator>>= (unsigned long k) { #if __GNU_MP_VERSION >= 4 mpq_div_2exp(rep, rep, k); #else if (mpz_sgn(mpq_numref(rep))) { unsigned long num0s=mpz_scan1(mpq_numref(rep), 0); if (k<=num0s) { mpz_tdiv_q_2exp(mpq_numref(rep), mpq_numref(rep), k); } else { mpz_tdiv_q_2exp(mpq_numref(rep), mpq_numref(rep), num0s); mpz_mul_2exp(mpq_denref(rep), mpq_denref(rep), k-num0s); } } #endif return *this; } friend Rational operator+ (const Rational& a, const Rational& b) { return Rational(mpq_add, a.rep, b.get_rep()); } friend Rational operator+ (const Rational& a, const Integer& b) { #if __GNU_MP_VERSION >= 4 return Rational(mpz_addmul, mpq_numref(a.rep), mpq_denref(a.rep), b.get_rep(), mpq_denref(a.rep)); #else Integer t=denominator(a)*b; return Rational(mpz_add, mpq_numref(a.rep), t.get_rep(), mpq_denref(a.rep)); #endif } friend Rational operator+ (const Rational& a, long b) { #if __GNU_MP_VERSION >= 4 if (b>=0) return Rational(mpz_addmul_ui, mpq_numref(a.rep), mpq_denref(a.rep), (unsigned long)b, mpq_denref(a.rep)); return Rational(mpz_submul_ui, mpq_numref(a.rep), mpq_denref(a.rep), (unsigned long)(-b), mpq_denref(a.rep)); #else mpz_t minus_den; mpz_srcptr den= b>=0 ? mpq_denref(a.rep) : (b=-b, Integer::_tmp_negate(minus_den,mpq_denref(a.rep))); return Rational(mpz_addmul_ui, mpq_numref(a.rep), den, (unsigned long)b, mpq_denref(a.rep)); #endif } friend Rational operator- (const Rational& a, const Rational& b) { return Rational(mpq_sub, a.rep, b.rep); } friend Rational operator- (const Rational& a, const Integer& b) { #if __GNU_MP_VERSION >= 4 return Rational(mpz_submul, mpq_numref(a.rep), mpq_denref(a.rep), b.get_rep(), mpq_denref(a.rep)); #else Integer t=denominator(a)*b; return Rational(mpz_sub, mpq_numref(a.rep), t.get_rep(), mpq_denref(a.rep)); #endif } friend Rational operator- (const Integer& a, const Rational& b) { #if __GNU_MP_VERSION >= 4 mpz_t minus_num; return Rational(mpz_addmul, Integer::_tmp_negate(minus_num,mpq_numref(b.rep)), mpq_denref(b.rep), a.get_rep(), mpq_denref(b.rep)); #else Integer t=denominator(b)*a; return Rational(mpz_sub, t.get_rep(), mpq_numref(b.rep), mpq_denref(b.rep)); #endif } friend Rational operator- (const Rational& a, long b) { #if __GNU_MP_VERSION >= 4 if (b>=0) return Rational(mpz_submul_ui, mpq_numref(a.rep), mpq_denref(a.rep), (unsigned long)b, mpq_denref(a.rep)); return Rational(mpz_addmul_ui, mpq_numref(a.rep), mpq_denref(a.rep), (unsigned long)(-b), mpq_denref(a.rep)); #else mpz_t minus_den; mpz_srcptr den= b>=0 ? Integer::_tmp_negate(minus_den,mpq_denref(a.rep)) : (b=-b, mpq_denref(a.rep)); return Rational(mpz_addmul_ui, mpq_numref(a.rep), den, (unsigned long)b, mpq_denref(a.rep)); #endif } friend Rational operator- (long a, const Rational& b) { mpz_t minus_num; Integer::_tmp_negate(minus_num,mpq_numref(b.rep)); #if __GNU_MP_VERSION >= 4 if (a>=0) return Rational(mpz_addmul_ui, minus_num, mpq_denref(b.rep), (unsigned long)a, mpq_denref(b.rep)); return Rational(mpz_submul_ui, minus_num, mpq_denref(b.rep), (unsigned long)(-a), mpq_denref(b.rep)); #else mpz_t minus_den; mpz_srcptr den= a>=0 ? mpq_denref(b.rep) : (a=-a, Integer::_tmp_negate(minus_den,mpq_denref(b.rep))); return Rational(mpz_addmul_ui, minus_num, den, (unsigned long)a, mpq_denref(b.rep)); #endif } friend Rational operator- (const Rational& a) { return Rational(mpq_neg,a.rep); } friend Rational operator* (const Rational& a, const Rational& b) { return Rational(mpq_mul,a.rep,b.rep); } friend Rational operator* (const Rational& a, const Integer& b); friend Rational operator* (const Rational& a, long b) { if (!b || !a) return Rational(); #if __GNU_MP_VERSION >= 4 unsigned long g=mpz_gcd_ui(0, mpq_denref(a.rep), b>=0 ? b : -b); if (g==1) return Rational(mpz_mul_si, mpq_numref(a.rep), b, mpq_denref(a.rep)); return Rational(mpz_mul_si, mpq_numref(a.rep), b/(long)g, mpz_divexact_ui, mpq_denref(a.rep), g); #else _tmp_little_Integer(g); if (mpz_gcd_ui(g, mpq_denref(a.rep), b>=0 ? b : -b) == 1) return Rational(mpz_mul_si, mpq_numref(a.rep), b, mpq_denref(a.rep)); return Rational(mpz_mul_si, mpq_numref(a.rep), b/(long)g_limb, mpz_divexact, mpq_denref(a.rep), const_cast<mpz_srcptr>(g)); #endif } friend Rational operator/ (const Rational& a, const Rational& b) { return Rational(mpq_div,a.rep,b.rep); } friend Rational operator/ (const Rational& a, long b) { if (!b) zero_division(); if (!a) return Rational(); mpz_t minus_num; mpz_srcptr num= b>0 ? mpq_numref(a.rep) : (b=-b, Integer::_tmp_negate(minus_num,mpq_numref(a.rep))); #if __GNU_MP_VERSION >= 4 unsigned long g=mpz_gcd_ui(0, mpq_numref(a.rep), b); if (g==1) return Rational(num, mpz_mul_ui, mpq_denref(a.rep), (unsigned long)b); return Rational(mpz_divexact_ui, num, g, mpz_mul_ui, mpq_denref(a.rep), b/g); #else _tmp_little_Integer(g); if (mpz_gcd_ui(g, mpq_numref(a.rep), b) == 1) return Rational(num, mpz_mul_ui, mpq_denref(a.rep), (unsigned long)b); return Rational(mpz_divexact, num, const_cast<mpz_srcptr>(g), mpz_mul_ui, mpq_denref(a.rep), b/g_limb); #endif } friend Rational operator/ (long a, const Rational& b) { if (!b) zero_division(); if (!a) return Rational(); mpz_t num_abs; mpz_srcptr num= mpz_sgn(mpq_numref(b.rep))>0 ? mpq_numref(b.rep) : (a=-a, Integer::_tmp_negate(num_abs,mpq_numref(b.rep))); #if __GNU_MP_VERSION >= 4 unsigned long g=mpz_gcd_ui(0, mpq_numref(b.rep), a>=0 ? a : -a); if (g==1) return Rational(mpz_mul_si, mpq_denref(b.rep), a, num); return Rational(mpz_mul_si, mpq_denref(b.rep), a/(long)g, mpz_divexact_ui, num, g); #else _tmp_little_Integer(g); if (mpz_gcd_ui(g, mpq_numref(b.rep), a>=0 ? a : -a) == 1) return Rational(mpz_mul_si, mpq_denref(b.rep), a, num); return Rational(mpz_mul_si, mpq_denref(b.rep), a/(long)g_limb, mpz_divexact, num, const_cast<mpz_srcptr>(g)); #endif } friend Rational operator/ (const Rational& a, const Integer& b) { if (!b) zero_division(); if (!a) return Rational(); const Integer g=gcd(numerator(a),b); if (g==1) return Rational(mpq_numref(a.rep), mpz_mul, mpq_denref(a.rep), b.get_rep()); const Integer t=div_exact(b,g); return Rational(mpz_divexact, mpq_numref(a.rep), g.get_rep(), mpz_mul, mpq_denref(a.rep), t.get_rep()); } friend Rational operator/ (const Integer& a, const Rational& b) { if (!b) zero_division(); if (!a) return Rational(); const Integer g=gcd(a,numerator(b)); if (g==1) return Rational(mpz_mul, mpq_denref(b.rep), a.get_rep(), mpq_numref(b.rep)); const Integer t=div_exact(a,g); return Rational(mpz_mul, mpq_denref(b.rep), t.get_rep(), mpz_divexact, mpq_numref(b.rep), g.get_rep()); } friend Rational floor(const Rational& a) { return Rational(mpz_fdiv_q, mpq_numref(a.rep), mpq_denref(a.rep), 1); } friend Rational ceil(const Rational& a) { return Rational(mpz_cdiv_q, mpq_numref(a.rep), mpq_denref(a.rep), 1); } /// Multiply with $2^k$ friend Rational operator<< (const Rational& a, unsigned long k) { #if __GNU_MP_VERSION >= 4 return Rational(mpq_mul_2exp, a.rep, k); #else if (!a) return Rational(0); unsigned long den0s=mpz_scan1(mpq_denref(a.rep), 0); if (k<=den0s) return Rational(mpq_numref(a.rep), mpz_tdiv_q_2exp, mpq_denref(a.rep), k); return Rational(mpz_mul_2exp, mpq_numref(a.rep), k-den0s, mpz_tdiv_q_2exp, mpq_denref(a.rep), den0s); #endif } /// Divide thru $2^k$ friend Rational operator>> (const Rational& a, unsigned long k) { #if __GNU_MP_VERSION >= 4 return Rational(mpq_div_2exp, a.rep, k); #else if (!a) return Rational(0); unsigned long num0s=mpz_scan1(mpq_numref(a.rep), 0); if (k<=num0s) return Rational(mpz_tdiv_q_2exp, mpq_numref(a.rep), k, mpq_denref(a.rep)); return Rational(mpz_tdiv_q_2exp, mpq_numref(a.rep), num0s, mpz_mul_2exp, mpq_denref(a.rep), k-num0s); #endif } /// Comparison. The magnitude of the return value is arbitrary, only its sign is relevant. int compare(const Rational& b) const { return mpq_cmp(rep, b.rep); } int compare(long b) const { return mpz_cmp_ui(mpq_denref(rep),1) ? numerator(*this).compare(b*denominator(*this)) : numerator(*this).compare(b); } int compare(const Integer& b) const { return mpz_cmp_ui(mpq_denref(rep),1) ? numerator(*this).compare(b*denominator(*this)) : numerator(*this).compare(b); } friend bool operator== (const Rational& a, const Rational& b) { #if __GNU_MP_VERSION >= 4 return mpq_equal(a.rep, b.rep); #else return !mpz_cmp(mpq_denref(a.rep), mpq_denref(b.rep)) && !mpz_cmp(mpq_numref(a.rep), mpq_numref(b.rep)); #endif } friend bool operator== (const Rational& a, const Integer& b) { return !mpz_cmp_ui(mpq_denref(a.rep),1) && !mpz_cmp(mpq_numref(a.rep), b.get_rep()); } friend bool operator== (const Rational& a, long b) { return !mpz_cmp_ui(mpq_denref(a.rep),1) && mpz_fits_slong_p(mpq_numref(a.rep)) && mpz_get_si(mpq_numref(a.rep))==b; } friend bool abs_equal(const Rational& a, const Rational& b) { return !mpz_cmp(mpq_denref(a.rep), mpq_denref(b.rep)) && !mpz_cmpabs(mpq_numref(a.rep), mpq_numref(b.rep)); } friend bool abs_equal(const Rational& a, const Integer& b) { return !mpz_cmp_ui(mpq_denref(a.rep),1) && !mpz_cmpabs(mpq_numref(a.rep), b.get_rep()); } friend bool abs_equal(const Rational& a, long b) { return !mpz_cmp_ui(mpq_denref(a.rep),1) && mpz_fits_slong_p(mpq_numref(a.rep)) && mpz_get_si(mpq_numref(a.rep))==std::abs(b); } friend Rational std::abs(const Rational& a); friend Rational inv(const Rational& a) { return Rational(mpq_inv, a.rep); } mpq_srcptr get_rep() const { return rep; } template <typename Traits> void read (std::basic_istream<char, Traits>& is) { numerator_nocanon(*this).read(is); if (!is.eof() && is.peek() == '/') { is.ignore(); denominator(*this).read(is,false); canonicalize(); } else { mpz_set_ui(mpq_denref(rep), 1); } } }; inline Rational operator+ (const Rational& a) { return a; } inline bool operator!= (const Rational& a, const Rational& b) { return !(a==b); } inline bool operator< (const Rational& a, const Rational& b) { return a.compare(b)<0; } inline bool operator> (const Rational& a, const Rational& b) { return a.compare(b)>0; } inline bool operator<= (const Rational& a, const Rational& b) { return a.compare(b)<=0; } inline bool operator>= (const Rational& a, const Rational& b) { return a.compare(b)>=0; } inline bool operator== (const temp_Rational& a, const temp_Rational& b) { return mpq_equal(&a,&b); } inline bool operator!= (const temp_Rational& a, const temp_Rational& b) { return !(a==b); } inline bool operator< (const temp_Rational& a, const temp_Rational& b) { return mpq_cmp(&a,&b)<0; } inline bool operator> (const temp_Rational& a, const temp_Rational& b) { return mpq_cmp(&a,&b)>0; } inline bool operator<= (const temp_Rational& a, const temp_Rational& b) { return mpq_cmp(&a,&b)<=0; } inline bool operator>= (const temp_Rational& a, const temp_Rational& b) { return mpq_cmp(&a,&b)>=0; } inline bool operator== (const Integer& a, const Rational& b) { return b==a; } inline bool operator== (long a, const Rational& b) { return b==a; } inline bool operator== (const Rational& a, int b) { return a==long(b); } inline bool operator== (int a, const Rational& b) { return b==long(a); } inline bool abs_equal(const Integer& a, const Rational& b) { return abs_equal(b,a); } inline bool abs_equal(long a, const Rational& b) { return abs_equal(b,a); } inline bool abs_equal(const Rational& a, int b) { return abs_equal(a,long(b)); } inline bool abs_equal(int a, const Rational& b) { return abs_equal(b,long(a)); } inline bool operator!= (const Rational& a, const Integer& b) { return !(a==b); } inline bool operator!= (const Integer& a, const Rational& b) { return !(b==a); } inline bool operator!= (const Rational& a, long b) { return !(a==b); } inline bool operator!= (long a, const Rational& b) { return !(b==a); } inline bool operator!= (const Rational& a, int b) { return !(a==b); } inline bool operator!= (int a, const Rational& b) { return !(b==a); } inline bool operator< (const Rational& a, const Integer& b) { return numerator(a) < b*denominator(a); } inline bool operator< (const Rational& a, long b) { return numerator(a) < b*denominator(a); } inline bool operator< (const Rational& a, int b) { return a < long(b); } inline bool operator> (const Rational& a, const Integer& b) { return numerator(a) > b*denominator(a); } inline bool operator> (const Rational& a, long b) { return numerator(a) > b*denominator(a); } inline bool operator> (const Rational& a, int b) { return a > long(b); } inline bool operator< (const Integer& a, const Rational& b) { return b>a; } inline bool operator< (long a, const Rational& b) { return b>a; } inline bool operator< (int a, const Rational& b) { return b>long(a); } inline bool operator> (const Integer& a, const Rational& b) { return b<a; } inline bool operator> (long a, const Rational& b) { return b<a; } inline bool operator> (int a, const Rational& b) { return b<long(a); } inline bool operator<= (const Rational& a, const Integer& b) { return !(a>b); } inline bool operator<= (const Integer& a, const Rational& b) { return !(b<a); } inline bool operator<= (const Rational& a, long b) { return !(a>b); } inline bool operator<= (const Rational& a, int b) { return !(a>long(b)); } inline bool operator<= (long a, const Rational& b) { return !(b<a); } inline bool operator<= (int a, const Rational& b) { return !(b<long(a)); } inline bool operator>= (const Rational& a, const Integer& b) { return !(a<b); } inline bool operator>= (const Rational& a, long b) { return !(a<b); } inline bool operator>= (const Rational& a, int b) { return !(a<long(b)); } inline bool operator>= (const Integer& a, const Rational& b) { return !(b>a); } inline bool operator>= (long a, const Rational& b) { return !(b>a); } inline bool operator>= (int a, const Rational& b) { return !(b>long(a)); } inline Integer& Integer::operator= (const Rational& r) { if (! mpz_cmp_ui(mpq_denref(r.rep),1)) mpz_set(rep,mpq_numref(r.rep)); else mpz_tdiv_q(rep, mpq_numref(r.rep), mpq_denref(r.rep)); return *this; } inline Integer::Integer(const Rational& r) { if (! mpz_cmp_ui(mpq_denref(r.rep),1)) { mpz_init_set(rep,mpq_numref(r.rep)); } else { mpz_init(rep); mpz_tdiv_q(rep, mpq_numref(r.rep), mpq_denref(r.rep)); } } inline Rational& Rational::operator*= (const Integer& b) { if (!*this) return *this; if (b) { Integer g=gcd(denominator(*this),b); if (g==1) { mpz_mul(mpq_numref(rep), mpq_numref(rep), b.rep); } else { mpz_divexact(mpq_denref(rep), mpq_denref(rep), g.rep); mpz_divexact(g.rep, b.rep, g.rep); mpz_mul(mpq_numref(rep), mpq_numref(rep), g.rep); } } else { *this=0; } return *this; } inline Rational& Rational::operator/= (const Integer& b) { if (!b) zero_division(); if (*this) { Integer g=gcd(numerator(*this),b); if (g==1) { mpz_mul(mpq_denref(rep), mpq_denref(rep), b.rep); } else { mpz_divexact(mpq_numref(rep), mpq_numref(rep), g.rep); mpz_divexact(g.rep, b.rep, g.rep); mpz_mul(mpq_denref(rep), mpq_denref(rep), g.rep); } } return *this; } inline Rational operator+ (const Rational& a, int b) { return a+long(b); } inline Rational operator+ (const Integer& a, const Rational& b) { return b+a; } inline Rational operator+ (long a, const Rational& b) { return b+a; } inline Rational operator+ (int a, const Rational& b) { return b+long(a); } inline Rational operator- (const Rational& a, int b) { return a-long(b); } inline Rational operator- (int a, const Rational& b) { return long(a)-b; } inline Rational operator* (const Rational& a, const Integer& b) { if (!a || !b) return Rational(); const Integer g=gcd(denominator(a),b); if (g==1) return Rational(mpz_mul, mpq_numref(a.rep), b.get_rep(), mpq_denref(a.rep)); const Integer t=div_exact(b,g); return Rational(mpz_mul, mpq_numref(a.rep), t.get_rep(), mpz_divexact, mpq_denref(a.rep), g.get_rep()); } inline Rational operator* (const Rational& a, int b) { return a*long(b); } inline Rational operator* (const Integer& a, const Rational& b) { return b*a; } inline Rational operator* (long a, const Rational& b) { return b*a; } inline Rational operator* (int a, const Rational& b) { return b*long(a); } inline Rational operator/ (const Rational& a, int b) { return a/long(b); } inline Rational operator/ (int a, const Rational& b) { return long(a)/b; } inline Rational operator<< (const Rational& a, unsigned int k) { return a << static_cast<unsigned long>(k); } inline Rational operator>> (const Rational& a, unsigned int k) { return a >> static_cast<unsigned long>(k); } inline Rational operator<< (const Rational& a, long k) { if (k<0) return a >> static_cast<unsigned long>(-k); return a << static_cast<unsigned long>(k); } inline Rational operator>> (const Rational& a, long k) { if (k<0) return a << static_cast<unsigned long>(-k); return a >> static_cast<unsigned long>(k); } inline Rational operator<< (const Rational& a, int k) { return a << long(k); } inline Rational operator>> (const Rational& a, int k) { return a >> long(k); } template <typename Traits> std::basic_ostream<char, Traits>& operator<< (std::basic_ostream<char, Traits>& os, const Rational& a) { bool show_den=false; int s=numerator(a).strsize(os.flags()); if (denominator(a)!=1) { show_den=true; s+=1+denominator(a).strsize(os.flags()); } Integer::little_buffer buf(s); numerator(a).putstr(os.flags(), buf); if (show_den) { char *den_buf=buf+strlen(buf); *den_buf++ = '/'; denominator(a).putstr(os.flags(), den_buf); } return os << static_cast<char*>(buf); } template <typename Traits> std::basic_istream<char, Traits>& operator>> (std::basic_istream<char, Traits>& is, Rational& a) { a.read(is); return is; } namespace std { inline void swap(::Rational& r1, ::Rational& r2) { r1.swap(r2); } inline Rational abs(const Rational& a) { return Rational(mpz_abs, mpq_numref(a.rep), mpq_denref(a.rep)); } template <> struct numeric_limits<Rational> : numeric_limits<Integer> { static const bool is_integer=false; }; } // end namespace std namespace std_ext { template <> struct hash<MP_RAT> : hash<MP_INT> { protected: size_t _do(mpq_srcptr a) const { return hash<MP_INT>::_do(mpq_numref(a)) - hash<MP_INT>::_do(mpq_denref(a)); } public: size_t operator() (const MP_RAT& a) const { return _do(&a); } }; template <> struct hash<Rational> : hash<MP_RAT> { size_t operator() (const Rational& a) const { return _do(a.get_rep()); } }; } // end namespace std_ext #endif // _POLYMAKE_GMP_RATIONAL_H // Local Variables: // mode:C++ // End: