numerix_doc 0.4
/Users/mourrain/Devel/mmx/numerix/include/numerix/rational.hpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : rational.hpp
00004 * DESCRIPTION: Rational numbers
00005 * COPYRIGHT  : (C) 2004  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license and comes WITHOUT
00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
00009 * If you don't have this file, write to the Free Software Foundation, Inc.,
00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00011 ******************************************************************************/
00012 
00013 #ifndef __MMX_RATIONAL_HPP
00014 #define __MMX_RATIONAL_HPP
00015 #include <numerix/integer.hpp>
00016 namespace mmx {
00017 
00018 class rational;
00019 class rational_rep;
00020 rational copy (const rational& i);
00021 
00022 /******************************************************************************
00023 * Rational numbers
00024 ******************************************************************************/
00025 
00026 class rational_rep REP_STRUCT {
00027 private:
00028   mpq_t x;
00029 public:
00030   inline rational_rep () { mpq_init (x); }
00031   inline ~rational_rep () { mpq_clear (x); }
00032   friend class rational;
00033   template<typename V> friend class floating;
00034 };
00035 
00036 class rational {
00037 INDIRECT_PROTO (rational, rational_rep)
00038 private:
00039   inline const mpq_t& operator * () const { return rep->x; }
00040   inline mpq_t& operator * () { secure(); return rep->x; }
00041 
00042 public:
00043   // constructors
00044   inline rational (): rep (new rational_rep ()) {}
00045   inline rational (signed int i): rep (new rational_rep ()) {
00046     mpq_set_si (rep->x, i, 1); }
00047   inline rational (unsigned int i):
00048     rep (new rational_rep ()) { mpq_set_ui (rep->x, i, 1); }
00049   inline rational (signed short int i):
00050     rep (new rational_rep ()) { mpq_set_si (rep->x, i, 1); }
00051   inline rational (unsigned short int i):
00052     rep (new rational_rep ()) { mpq_set_ui (rep->x, i, 1); }
00053   inline rational (signed long int i):
00054     rep (new rational_rep ()) { mpq_set_si (rep->x, i, 1); }
00055   inline rational (unsigned long int i):
00056     rep (new rational_rep ()) { mpq_set_ui (rep->x, i, 1); }
00057   inline rational (const integer& i):
00058     rep (new rational_rep ()) { mpq_set_z (rep->x, *i); }
00059   inline rational (const double& d):
00060     rep (new rational_rep ()) { mpq_set_d (rep->x, d); }
00061 
00062   inline rational (char * const & c):
00063     rep (new rational_rep ()) { mpq_set_str (rep->x, c, 10); }
00064 
00065   // getting the numerator and denominator
00066   inline friend integer numerator (const rational& x1) {
00067     integer r; mpq_get_num (*r, *x1); return r; }
00068   inline friend integer denominator (const rational& x1) {
00069     integer r; mpq_get_den (*r, *x1); return r; }
00070 
00071   // basic arithmetic
00072   inline friend rational copy (const rational& x1) {
00073     rational r; mpq_set (*r, *x1); return r; }
00074   inline friend rational operator - (const rational& x1) {
00075     rational r; mpq_neg (*r, *x1); return r; }
00076   inline friend rational operator + (const rational& x1, const rational& x2) {
00077     rational r; mpq_add (*r, *x1, *x2); return r; }
00078   inline friend rational operator - (const rational& x1, const rational& x2) {
00079     rational r; mpq_sub (*r, *x1, *x2); return r; }
00080   inline friend rational operator * (const rational& x1, const rational& x2) {
00081     rational r; mpq_mul (*r, *x1, *x2); return r; }
00082   inline friend rational square (const rational& x1) {
00083     rational r; mpq_mul (*r, *x1, *x1); return r; }
00084   inline friend rational operator / (const rational& x1, const rational& x2) {
00085     ASSERT (mpq_sgn (*x2) != 0, "division by zero");
00086     rational r; mpq_div (*r, *x1, *x2); return r; }
00087   inline friend bool divides (const rational& x1, const rational& x2) {
00088     return mpq_sgn (*x1) != 0; }
00089   inline friend rational invert (const rational& x) {
00090     return rational (1) / x; }
00091   inline friend rational operator << (const rational& x1, const xint& shift) {
00092     rational r; mpq_mul_2si (*r, *x1, shift); return r; }
00093   inline friend rational operator >> (const rational& x1, const xint& shift) {
00094     rational r; mpq_mul_2si (*r, *x1, -shift); return r; }
00095   inline friend rational abs (const rational& x1) {
00096     rational r; mpq_abs (*r, *x1); return r; }
00097 
00098   // in-place arithmetic
00099   inline friend rational& operator += (rational& x1, const rational& x2) {
00100     x1.secure (); mpq_add (*x1, *x1, *x2); return x1; }
00101   inline friend rational& operator -= (rational& x1, const rational& x2) {
00102     x1.secure (); mpq_sub (*x1, *x1, *x2); return x1; }
00103   inline friend rational& operator *= (rational& x1, const rational& x2) {
00104     x1.secure (); mpq_mul (*x1, *x1, *x2); return x1; }
00105   inline friend rational& operator /= (rational& x1, const rational& x2) {
00106     ASSERT (mpq_sgn (*x2) != 0, "division by zero");
00107     x1.secure (); mpq_div (*x1, *x1, *x2); return x1; }
00108   inline friend rational& operator <<= (rational& x1, const xint& shift) {
00109     x1.secure (); mpq_mul_2si (*x1, *x1, shift); return x1; }
00110   inline friend rational& operator >>= (rational& x1, const xint& shift) {
00111     x1.secure (); mpq_mul_2si (*x1, *x1, -shift); return x1; }
00112 
00113   inline friend void
00114   neg (rational& r) {
00115     r.secure (); mpq_neg (*r, *r); }
00116   inline friend void
00117   neg (rational& r, const rational& x1) {
00118     r.secure (); mpq_neg (*r, *x1); }
00119   inline friend void
00120   add (rational& r, const rational& x1, const rational& x2) {
00121     r.secure (); mpq_add (*r, *x1, *x2); }
00122   inline friend void
00123   sub (rational& r, const rational& x1, const rational& x2) {
00124     r.secure (); mpq_sub (*r, *x1, *x2); }
00125   inline friend void
00126   mul (rational& r, const rational& x1, const rational& x2) {
00127     r.secure (); mpq_mul (*r, *x1, *x2); }
00128   inline friend void
00129   div (rational& r, const rational& x1, const rational& x2) {
00130     ASSERT (mpq_sgn (*x2) != 0, "division by zero");
00131     r.secure (); mpq_div (*r, *x1, *x2); }
00132 
00133   // comparing rational numbers
00134   inline friend bool operator == (const rational& x1, const rational& x2) {
00135     return mpq_cmp (*x1, *x2) == 0; }
00136   inline friend bool operator != (const rational& x1, const rational& x2) {
00137     return mpq_cmp (*x1, *x2) != 0; }
00138   inline friend bool operator < (const rational& x1, const rational& x2) {
00139     return mpq_cmp (*x1, *x2) < 0; }
00140   inline friend bool operator > (const rational& x1, const rational& x2) {
00141     return mpq_cmp (*x1, *x2) > 0; }
00142   inline friend bool operator <= (const rational& x1, const rational& x2) {
00143     return mpq_cmp (*x1, *x2) <= 0; }
00144   inline friend bool operator >= (const rational& x1, const rational& x2) {
00145     return mpq_cmp (*x1, *x2) >= 0; }
00146   inline friend int sign (const rational& x1) {
00147     int r= mpq_sgn (*x1); return (r<0? -1: (r==0? 0: 1)); }
00148   inline friend rational min (const rational& x1, const rational& x2) {
00149     return x1 <= x2? x1: x2; }
00150   inline friend rational max (const rational& x1, const rational& x2) {
00151     return x1 >= x2? x1: x2; }
00152 
00153   // rounding towards integers
00154   inline friend rational floor (const rational& x1) {
00155     return quo (numerator (x1), denominator (x1)); }
00156   inline friend rational trunc (const rational& x1) {
00157     return sign (x1) * quo (abs (numerator (x1)), denominator (x1)); }
00158   inline friend rational ceil (const rational& x1) {
00159     return quo (numerator (x1) + denominator (x1) - 1, denominator (x1)); }
00160   inline friend rational round (const rational& x1) {
00161     return quo (numerator (x1) + (denominator (x1) >> 1), denominator (x1)); }
00162 
00163   // other functions on rationals
00164   inline friend bool is_square (const rational& a) {
00165     return mpz_perfect_square_p (mpq_numref (*a)) &&
00166            mpz_perfect_square_p (mpq_denref (*a)); }
00167   inline friend rational sqrt (const rational& a) {
00168     VERIFY (is_square (a), "not a perfect square");
00169     rational r;
00170     mpz_sqrt (mpq_numref (*r), mpq_numref (*a));
00171     mpz_sqrt (mpq_denref (*r), mpq_denref (*a));
00172     return r; }
00173   inline friend rational pow (const rational& a, const int& i) {
00174     rational r;
00175     if (i >= 0) {
00176       mpz_pow_ui (mpq_numref (*r), mpq_numref (*a), i);
00177       mpz_pow_ui (mpq_denref (*r), mpq_denref (*a), i);
00178     }
00179     else {
00180       ASSERT (mpq_sgn (*a) != 0, "division by zero");
00181       mpz_pow_ui (mpq_denref (*r), mpq_numref (*a), -i);
00182       mpz_pow_ui (mpq_numref (*r), mpq_denref (*a), -i);
00183     }
00184     return r; }
00185   inline friend rational pow (const rational& a, const integer& i) {
00186     // FIXME: test whether integer i fits in int
00187     return pow (a, as_int (i)); }
00188 
00189   // miscellaneous functions
00190   inline friend nat hash (const rational& x) {
00191     const __mpq_struct &rep= (*x)[0];
00192     if (rep._mp_num._mp_size == 0) return 0;
00193     return
00194       ((nat) (rep._mp_num._mp_d[0])) ^
00195       ((nat) (rep._mp_num._mp_size << 3)) ^
00196       ((nat) (rep._mp_den._mp_d[0] << 7)) ^
00197       ((nat) (rep._mp_den._mp_size << 11));
00198   }
00199 
00200   template<typename V> friend class floating;
00201   template<typename V> friend floating<V> as_floating (const rational& x);
00202   friend double as_double (const rational& q)  {return mpq_get_d(*q);}
00203 };
00204 INDIRECT_IMPL (rational, rational_rep)
00205 
00206 template<> struct symbolic_type_information<rational> {
00207   static const nat id= SYMBOLIC_RATIONAL; };
00208 
00209 UNARY_RETURN_TYPE(STMPL,numerator_op,rational,integer);
00210 UNARY_RETURN_TYPE(STMPL,denominator_op,rational,integer);
00211 
00212 /******************************************************************************
00213 * Conversion related
00214 ******************************************************************************/
00215 
00216 syntactic flatten (const rational& x);
00217 
00218 template<>
00219 struct binary_helper<rational>: public void_binary_helper<rational> {
00220   static inline string short_type_name () { return "Q"; }
00221   static inline generic full_type_name () { return "Rational"; }
00222   static inline generic disassemble (const rational& x) {
00223     return gen_vec (as<generic> (numerator (x)),
00224                     as<generic> (denominator (x))); }
00225   static inline rational assemble (const generic& v) {
00226     return rational (as<integer> (vector_access (v, 0))) /
00227            rational (as<integer> (vector_access (v, 1))); }
00228   static inline void write (const port& out, const rational& x) {
00229     binary_write<integer> (out, numerator (x));
00230     binary_write<integer> (out, denominator (x)); }
00231   static inline rational read (const port& in) {
00232     integer n= binary_read<integer> (in);
00233     integer d= binary_read<integer> (in);
00234     return rational (n) / rational (d); }
00235 };
00236 
00237 template<>
00238 struct as_helper<double,rational> {
00239   static inline double cv (const rational& x) { return as_double (x); }
00240 };
00241 
00242 template<typename F> inline rational
00243 promote (const F& x, const rational&) { return as<rational> (x); }
00244 
00245 /******************************************************************************
00246 * Defaults
00247 ******************************************************************************/
00248 
00249 generic construct (const rational& x);
00250 template<> inline rational duplicate (const rational& x) { return copy (x); }
00251 inline void set_nan (rational& r) { r= 0; }
00252 
00253 TRUE_TO_EXACT_IDENTITY_SUGAR(,rational)
00254 ARITH_INT_SUGAR(,rational)
00255 GCD_SUGAR(,rational)
00256 POOR_MAN_ELEMENTARY_SUGAR(,rational)
00257 
00258 /******************************************************************************
00259 * Extras for glue
00260 ******************************************************************************/
00261 
00262 #define rational_new(n,d) rational(n)/d
00263 #define integer_pow(i,j) (j>=0?as<generic>(pow(i,j)):as<generic>(1/rational(pow(i,-j))))
00264   // FIXME: to be removed
00265 
00266 }
00267 #endif // __MMX_RATIONAL_HPP
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines