numerix_doc 0.4
|
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