• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

rational.c

Go to the documentation of this file.
00001 /*
00002   rational.c: Coded by Tadayoshi Funaba 2008,2009
00003 
00004   This implementation is based on Keiju Ishitsuka's Rational library
00005   which is written in ruby.
00006 */
00007 
00008 #include "ruby.h"
00009 #include <math.h>
00010 #include <float.h>
00011 
00012 #ifdef HAVE_IEEEFP_H
00013 #include <ieeefp.h>
00014 #endif
00015 
00016 #define NDEBUG
00017 #include <assert.h>
00018 
00019 #define ZERO INT2FIX(0)
00020 #define ONE INT2FIX(1)
00021 #define TWO INT2FIX(2)
00022 
00023 VALUE rb_cRational;
00024 
00025 static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv,
00026     id_floor, id_idiv, id_inspect, id_integer_p, id_negate, id_to_f,
00027     id_to_i, id_to_s, id_truncate;
00028 
00029 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
00030 
00031 #define binop(n,op) \
00032 inline static VALUE \
00033 f_##n(VALUE x, VALUE y)\
00034 {\
00035   return rb_funcall(x, op, 1, y);\
00036 }
00037 
00038 #define fun1(n) \
00039 inline static VALUE \
00040 f_##n(VALUE x)\
00041 {\
00042     return rb_funcall(x, id_##n, 0);\
00043 }
00044 
00045 #define fun2(n) \
00046 inline static VALUE \
00047 f_##n(VALUE x, VALUE y)\
00048 {\
00049     return rb_funcall(x, id_##n, 1, y);\
00050 }
00051 
00052 inline static VALUE
00053 f_add(VALUE x, VALUE y)
00054 {
00055     if (FIXNUM_P(y) && FIX2LONG(y) == 0)
00056         return x;
00057     else if (FIXNUM_P(x) && FIX2LONG(x) == 0)
00058         return y;
00059     return rb_funcall(x, '+', 1, y);
00060 }
00061 
00062 inline static VALUE
00063 f_cmp(VALUE x, VALUE y)
00064 {
00065     if (FIXNUM_P(x) && FIXNUM_P(y)) {
00066         long c = FIX2LONG(x) - FIX2LONG(y);
00067         if (c > 0)
00068             c = 1;
00069         else if (c < 0)
00070             c = -1;
00071         return INT2FIX(c);
00072     }
00073     return rb_funcall(x, id_cmp, 1, y);
00074 }
00075 
00076 inline static VALUE
00077 f_div(VALUE x, VALUE y)
00078 {
00079     if (FIXNUM_P(y) && FIX2LONG(y) == 1)
00080         return x;
00081     return rb_funcall(x, '/', 1, y);
00082 }
00083 
00084 inline static VALUE
00085 f_gt_p(VALUE x, VALUE y)
00086 {
00087     if (FIXNUM_P(x) && FIXNUM_P(y))
00088         return f_boolcast(FIX2LONG(x) > FIX2LONG(y));
00089     return rb_funcall(x, '>', 1, y);
00090 }
00091 
00092 inline static VALUE
00093 f_lt_p(VALUE x, VALUE y)
00094 {
00095     if (FIXNUM_P(x) && FIXNUM_P(y))
00096         return f_boolcast(FIX2LONG(x) < FIX2LONG(y));
00097     return rb_funcall(x, '<', 1, y);
00098 }
00099 
00100 binop(mod, '%')
00101 
00102 inline static VALUE
00103 f_mul(VALUE x, VALUE y)
00104 {
00105     if (FIXNUM_P(y)) {
00106         long iy = FIX2LONG(y);
00107         if (iy == 0) {
00108             if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM)
00109                 return ZERO;
00110         }
00111         else if (iy == 1)
00112             return x;
00113     }
00114     else if (FIXNUM_P(x)) {
00115         long ix = FIX2LONG(x);
00116         if (ix == 0) {
00117             if (FIXNUM_P(y) || TYPE(y) == T_BIGNUM)
00118                 return ZERO;
00119         }
00120         else if (ix == 1)
00121             return y;
00122     }
00123     return rb_funcall(x, '*', 1, y);
00124 }
00125 
00126 inline static VALUE
00127 f_sub(VALUE x, VALUE y)
00128 {
00129     if (FIXNUM_P(y) && FIX2LONG(y) == 0)
00130         return x;
00131     return rb_funcall(x, '-', 1, y);
00132 }
00133 
00134 fun1(abs)
00135 fun1(floor)
00136 fun1(inspect)
00137 fun1(integer_p)
00138 fun1(negate)
00139 fun1(to_f)
00140 fun1(to_i)
00141 fun1(to_s)
00142 fun1(truncate)
00143 
00144 inline static VALUE
00145 f_eqeq_p(VALUE x, VALUE y)
00146 {
00147     if (FIXNUM_P(x) && FIXNUM_P(y))
00148         return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
00149     return rb_funcall(x, id_eqeq_p, 1, y);
00150 }
00151 
00152 fun2(expt)
00153 fun2(fdiv)
00154 fun2(idiv)
00155 
00156 inline static VALUE
00157 f_negative_p(VALUE x)
00158 {
00159     if (FIXNUM_P(x))
00160         return f_boolcast(FIX2LONG(x) < 0);
00161     return rb_funcall(x, '<', 1, ZERO);
00162 }
00163 
00164 #define f_positive_p(x) (!f_negative_p(x))
00165 
00166 inline static VALUE
00167 f_zero_p(VALUE x)
00168 {
00169     switch (TYPE(x)) {
00170       case T_FIXNUM:
00171         return f_boolcast(FIX2LONG(x) == 0);
00172       case T_BIGNUM:
00173         return Qfalse;
00174       case T_RATIONAL:
00175       {
00176           VALUE num = RRATIONAL(x)->num;
00177 
00178           return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0);
00179       }
00180     }
00181     return rb_funcall(x, id_eqeq_p, 1, ZERO);
00182 }
00183 
00184 #define f_nonzero_p(x) (!f_zero_p(x))
00185 
00186 inline static VALUE
00187 f_one_p(VALUE x)
00188 {
00189     switch (TYPE(x)) {
00190       case T_FIXNUM:
00191         return f_boolcast(FIX2LONG(x) == 1);
00192       case T_BIGNUM:
00193         return Qfalse;
00194       case T_RATIONAL:
00195       {
00196           VALUE num = RRATIONAL(x)->num;
00197           VALUE den = RRATIONAL(x)->den;
00198 
00199           return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 1 &&
00200                             FIXNUM_P(den) && FIX2LONG(den) == 1);
00201       }
00202     }
00203     return rb_funcall(x, id_eqeq_p, 1, ONE);
00204 }
00205 
00206 inline static VALUE
00207 f_kind_of_p(VALUE x, VALUE c)
00208 {
00209     return rb_obj_is_kind_of(x, c);
00210 }
00211 
00212 inline static VALUE
00213 k_numeric_p(VALUE x)
00214 {
00215     return f_kind_of_p(x, rb_cNumeric);
00216 }
00217 
00218 inline static VALUE
00219 k_integer_p(VALUE x)
00220 {
00221     return f_kind_of_p(x, rb_cInteger);
00222 }
00223 
00224 inline static VALUE
00225 k_float_p(VALUE x)
00226 {
00227     return f_kind_of_p(x, rb_cFloat);
00228 }
00229 
00230 inline static VALUE
00231 k_rational_p(VALUE x)
00232 {
00233     return f_kind_of_p(x, rb_cRational);
00234 }
00235 
00236 #define k_exact_p(x) (!k_float_p(x))
00237 #define k_inexact_p(x) k_float_p(x)
00238 
00239 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
00240 #define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
00241 
00242 #ifndef NDEBUG
00243 #define f_gcd f_gcd_orig
00244 #endif
00245 
00246 inline static long
00247 i_gcd(long x, long y)
00248 {
00249     if (x < 0)
00250         x = -x;
00251     if (y < 0)
00252         y = -y;
00253 
00254     if (x == 0)
00255         return y;
00256     if (y == 0)
00257         return x;
00258 
00259     while (x > 0) {
00260         long t = x;
00261         x = y % x;
00262         y = t;
00263     }
00264     return y;
00265 }
00266 
00267 inline static VALUE
00268 f_gcd(VALUE x, VALUE y)
00269 {
00270     VALUE z;
00271 
00272     if (FIXNUM_P(x) && FIXNUM_P(y))
00273         return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
00274 
00275     if (f_negative_p(x))
00276         x = f_negate(x);
00277     if (f_negative_p(y))
00278         y = f_negate(y);
00279 
00280     if (f_zero_p(x))
00281         return y;
00282     if (f_zero_p(y))
00283         return x;
00284 
00285     for (;;) {
00286         if (FIXNUM_P(x)) {
00287             if (FIX2LONG(x) == 0)
00288                 return y;
00289             if (FIXNUM_P(y))
00290                 return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
00291         }
00292         z = x;
00293         x = f_mod(y, x);
00294         y = z;
00295     }
00296     /* NOTREACHED */
00297 }
00298 
00299 #ifndef NDEBUG
00300 #undef f_gcd
00301 
00302 inline static VALUE
00303 f_gcd(VALUE x, VALUE y)
00304 {
00305     VALUE r = f_gcd_orig(x, y);
00306     if (f_nonzero_p(r)) {
00307         assert(f_zero_p(f_mod(x, r)));
00308         assert(f_zero_p(f_mod(y, r)));
00309     }
00310     return r;
00311 }
00312 #endif
00313 
00314 inline static VALUE
00315 f_lcm(VALUE x, VALUE y)
00316 {
00317     if (f_zero_p(x) || f_zero_p(y))
00318         return ZERO;
00319     return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
00320 }
00321 
00322 #define get_dat1(x) \
00323     struct RRational *dat;\
00324     dat = ((struct RRational *)(x))
00325 
00326 #define get_dat2(x,y) \
00327     struct RRational *adat, *bdat;\
00328     adat = ((struct RRational *)(x));\
00329     bdat = ((struct RRational *)(y))
00330 
00331 inline static VALUE
00332 nurat_s_new_internal(VALUE klass, VALUE num, VALUE den)
00333 {
00334     NEWOBJ(obj, struct RRational);
00335     OBJSETUP(obj, klass, T_RATIONAL);
00336 
00337     obj->num = num;
00338     obj->den = den;
00339 
00340     return (VALUE)obj;
00341 }
00342 
00343 static VALUE
00344 nurat_s_alloc(VALUE klass)
00345 {
00346     return nurat_s_new_internal(klass, ZERO, ONE);
00347 }
00348 
00349 #define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
00350 
00351 #if 0
00352 static VALUE
00353 nurat_s_new_bang(int argc, VALUE *argv, VALUE klass)
00354 {
00355     VALUE num, den;
00356 
00357     switch (rb_scan_args(argc, argv, "11", &num, &den)) {
00358       case 1:
00359         if (!k_integer_p(num))
00360             num = f_to_i(num);
00361         den = ONE;
00362         break;
00363       default:
00364         if (!k_integer_p(num))
00365             num = f_to_i(num);
00366         if (!k_integer_p(den))
00367             den = f_to_i(den);
00368 
00369         switch (FIX2INT(f_cmp(den, ZERO))) {
00370           case -1:
00371             num = f_negate(num);
00372             den = f_negate(den);
00373             break;
00374           case 0:
00375             rb_raise_zerodiv();
00376             break;
00377         }
00378         break;
00379     }
00380 
00381     return nurat_s_new_internal(klass, num, den);
00382 }
00383 #endif
00384 
00385 inline static VALUE
00386 f_rational_new_bang1(VALUE klass, VALUE x)
00387 {
00388     return nurat_s_new_internal(klass, x, ONE);
00389 }
00390 
00391 inline static VALUE
00392 f_rational_new_bang2(VALUE klass, VALUE x, VALUE y)
00393 {
00394     assert(f_positive_p(y));
00395     assert(f_nonzero_p(y));
00396     return nurat_s_new_internal(klass, x, y);
00397 }
00398 
00399 #ifdef CANONICALIZATION_FOR_MATHN
00400 #define CANON
00401 #endif
00402 
00403 #ifdef CANON
00404 static int canonicalization = 0;
00405 
00406 void
00407 nurat_canonicalization(int f)
00408 {
00409     canonicalization = f;
00410 }
00411 #endif
00412 
00413 inline static void
00414 nurat_int_check(VALUE num)
00415 {
00416     switch (TYPE(num)) {
00417       case T_FIXNUM:
00418       case T_BIGNUM:
00419         break;
00420       default:
00421         if (!k_numeric_p(num) || !f_integer_p(num))
00422             rb_raise(rb_eTypeError, "not an integer");
00423     }
00424 }
00425 
00426 inline static VALUE
00427 nurat_int_value(VALUE num)
00428 {
00429     nurat_int_check(num);
00430     if (!k_integer_p(num))
00431         num = f_to_i(num);
00432     return num;
00433 }
00434 
00435 inline static VALUE
00436 nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den)
00437 {
00438     VALUE gcd;
00439 
00440     switch (FIX2INT(f_cmp(den, ZERO))) {
00441       case -1:
00442         num = f_negate(num);
00443         den = f_negate(den);
00444         break;
00445       case 0:
00446         rb_raise_zerodiv();
00447         break;
00448     }
00449 
00450     gcd = f_gcd(num, den);
00451     num = f_idiv(num, gcd);
00452     den = f_idiv(den, gcd);
00453 
00454 #ifdef CANON
00455     if (f_one_p(den) && canonicalization)
00456         return num;
00457 #endif
00458     return nurat_s_new_internal(klass, num, den);
00459 }
00460 
00461 inline static VALUE
00462 nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den)
00463 {
00464     switch (FIX2INT(f_cmp(den, ZERO))) {
00465       case -1:
00466         num = f_negate(num);
00467         den = f_negate(den);
00468         break;
00469       case 0:
00470         rb_raise_zerodiv();
00471         break;
00472     }
00473 
00474 #ifdef CANON
00475     if (f_one_p(den) && canonicalization)
00476         return num;
00477 #endif
00478     return nurat_s_new_internal(klass, num, den);
00479 }
00480 
00481 static VALUE
00482 nurat_s_new(int argc, VALUE *argv, VALUE klass)
00483 {
00484     VALUE num, den;
00485 
00486     switch (rb_scan_args(argc, argv, "11", &num, &den)) {
00487       case 1:
00488         num = nurat_int_value(num);
00489         den = ONE;
00490         break;
00491       default:
00492         num = nurat_int_value(num);
00493         den = nurat_int_value(den);
00494         break;
00495     }
00496 
00497     return nurat_s_canonicalize_internal(klass, num, den);
00498 }
00499 
00500 inline static VALUE
00501 f_rational_new1(VALUE klass, VALUE x)
00502 {
00503     assert(!k_rational_p(x));
00504     return nurat_s_canonicalize_internal(klass, x, ONE);
00505 }
00506 
00507 inline static VALUE
00508 f_rational_new2(VALUE klass, VALUE x, VALUE y)
00509 {
00510     assert(!k_rational_p(x));
00511     assert(!k_rational_p(y));
00512     return nurat_s_canonicalize_internal(klass, x, y);
00513 }
00514 
00515 inline static VALUE
00516 f_rational_new_no_reduce1(VALUE klass, VALUE x)
00517 {
00518     assert(!k_rational_p(x));
00519     return nurat_s_canonicalize_internal_no_reduce(klass, x, ONE);
00520 }
00521 
00522 inline static VALUE
00523 f_rational_new_no_reduce2(VALUE klass, VALUE x, VALUE y)
00524 {
00525     assert(!k_rational_p(x));
00526     assert(!k_rational_p(y));
00527     return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
00528 }
00529 
00530 /*
00531  * call-seq:
00532  *    Rational(x[, y])  ->  numeric
00533  *
00534  * Returns x/y;
00535  */
00536 static VALUE
00537 nurat_f_rational(int argc, VALUE *argv, VALUE klass)
00538 {
00539     return rb_funcall2(rb_cRational, id_convert, argc, argv);
00540 }
00541 
00542 /*
00543  * call-seq:
00544  *    rat.numerator  ->  integer
00545  *
00546  * Returns the numerator.
00547  *
00548  * For example:
00549  *
00550  *    Rational(7).numerator        #=> 7
00551  *    Rational(7, 1).numerator     #=> 7
00552  *    Rational(9, -4).numerator    #=> -9
00553  *    Rational(-2, -10).numerator  #=> 1
00554  */
00555 static VALUE
00556 nurat_numerator(VALUE self)
00557 {
00558     get_dat1(self);
00559     return dat->num;
00560 }
00561 
00562 /*
00563  * call-seq:
00564  *    rat.denominator  ->  integer
00565  *
00566  * Returns the denominator (always positive).
00567  *
00568  * For example:
00569  *
00570  *    Rational(7).denominator             #=> 1
00571  *    Rational(7, 1).denominator          #=> 1
00572  *    Rational(9, -4).denominator         #=> 4
00573  *    Rational(-2, -10).denominator       #=> 5
00574  *    rat.numerator.gcd(rat.denominator)  #=> 1
00575  */
00576 static VALUE
00577 nurat_denominator(VALUE self)
00578 {
00579     get_dat1(self);
00580     return dat->den;
00581 }
00582 
00583 #ifndef NDEBUG
00584 #define f_imul f_imul_orig
00585 #endif
00586 
00587 inline static VALUE
00588 f_imul(long a, long b)
00589 {
00590     VALUE r;
00591     long c;
00592 
00593     if (a == 0 || b == 0)
00594         return ZERO;
00595     else if (a == 1)
00596         return LONG2NUM(b);
00597     else if (b == 1)
00598         return LONG2NUM(a);
00599 
00600     c = a * b;
00601     r = LONG2NUM(c);
00602     if (NUM2LONG(r) != c || (c / a) != b)
00603         r = rb_big_mul(rb_int2big(a), rb_int2big(b));
00604     return r;
00605 }
00606 
00607 #ifndef NDEBUG
00608 #undef f_imul
00609 
00610 inline static VALUE
00611 f_imul(long x, long y)
00612 {
00613     VALUE r = f_imul_orig(x, y);
00614     assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
00615     return r;
00616 }
00617 #endif
00618 
00619 inline static VALUE
00620 f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
00621 {
00622     VALUE num, den;
00623 
00624     if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
00625         FIXNUM_P(bnum) && FIXNUM_P(bden)) {
00626         long an = FIX2LONG(anum);
00627         long ad = FIX2LONG(aden);
00628         long bn = FIX2LONG(bnum);
00629         long bd = FIX2LONG(bden);
00630         long ig = i_gcd(ad, bd);
00631 
00632         VALUE g = LONG2NUM(ig);
00633         VALUE a = f_imul(an, bd / ig);
00634         VALUE b = f_imul(bn, ad / ig);
00635         VALUE c;
00636 
00637         if (k == '+')
00638             c = f_add(a, b);
00639         else
00640             c = f_sub(a, b);
00641 
00642         b = f_idiv(aden, g);
00643         g = f_gcd(c, g);
00644         num = f_idiv(c, g);
00645         a = f_idiv(bden, g);
00646         den = f_mul(a, b);
00647     }
00648     else {
00649         VALUE g = f_gcd(aden, bden);
00650         VALUE a = f_mul(anum, f_idiv(bden, g));
00651         VALUE b = f_mul(bnum, f_idiv(aden, g));
00652         VALUE c;
00653 
00654         if (k == '+')
00655             c = f_add(a, b);
00656         else
00657             c = f_sub(a, b);
00658 
00659         b = f_idiv(aden, g);
00660         g = f_gcd(c, g);
00661         num = f_idiv(c, g);
00662         a = f_idiv(bden, g);
00663         den = f_mul(a, b);
00664     }
00665     return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
00666 }
00667 
00668 /*
00669  * call-seq:
00670  *    rat + numeric  ->  numeric_result
00671  *
00672  * Performs addition.
00673  *
00674  * For example:
00675  *
00676  *    Rational(2, 3)  + Rational(2, 3)   #=> (4/3)
00677  *    Rational(900)   + Rational(1)      #=> (900/1)
00678  *    Rational(-2, 9) + Rational(-9, 2)  #=> (-85/18)
00679  *    Rational(9, 8)  + 4                #=> (41/8)
00680  *    Rational(20, 9) + 9.8              #=> 12.022222222222222
00681  */
00682 static VALUE
00683 nurat_add(VALUE self, VALUE other)
00684 {
00685     switch (TYPE(other)) {
00686       case T_FIXNUM:
00687       case T_BIGNUM:
00688         {
00689             get_dat1(self);
00690 
00691             return f_addsub(self,
00692                             dat->num, dat->den,
00693                             other, ONE, '+');
00694         }
00695       case T_FLOAT:
00696         return f_add(f_to_f(self), other);
00697       case T_RATIONAL:
00698         {
00699             get_dat2(self, other);
00700 
00701             return f_addsub(self,
00702                             adat->num, adat->den,
00703                             bdat->num, bdat->den, '+');
00704         }
00705       default:
00706         return rb_num_coerce_bin(self, other, '+');
00707     }
00708 }
00709 
00710 /*
00711  * call-seq:
00712  *    rat - numeric  ->  numeric_result
00713  *
00714  * Performs subtraction.
00715  *
00716  * For example:
00717  *
00718  *    Rational(2, 3)  - Rational(2, 3)   #=> (0/1)
00719  *    Rational(900)   - Rational(1)      #=> (899/1)
00720  *    Rational(-2, 9) - Rational(-9, 2)  #=> (77/18)
00721  *    Rational(9, 8)  - 4                #=> (23/8)
00722  *    Rational(20, 9) - 9.8              #=> -7.577777777777778
00723  */
00724 static VALUE
00725 nurat_sub(VALUE self, VALUE other)
00726 {
00727     switch (TYPE(other)) {
00728       case T_FIXNUM:
00729       case T_BIGNUM:
00730         {
00731             get_dat1(self);
00732 
00733             return f_addsub(self,
00734                             dat->num, dat->den,
00735                             other, ONE, '-');
00736         }
00737       case T_FLOAT:
00738         return f_sub(f_to_f(self), other);
00739       case T_RATIONAL:
00740         {
00741             get_dat2(self, other);
00742 
00743             return f_addsub(self,
00744                             adat->num, adat->den,
00745                             bdat->num, bdat->den, '-');
00746         }
00747       default:
00748         return rb_num_coerce_bin(self, other, '-');
00749     }
00750 }
00751 
00752 inline static VALUE
00753 f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
00754 {
00755     VALUE num, den;
00756 
00757     if (k == '/') {
00758         VALUE t;
00759 
00760         if (f_negative_p(bnum)) {
00761             anum = f_negate(anum);
00762             bnum = f_negate(bnum);
00763         }
00764         t = bnum;
00765         bnum = bden;
00766         bden = t;
00767     }
00768 
00769     if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
00770         FIXNUM_P(bnum) && FIXNUM_P(bden)) {
00771         long an = FIX2LONG(anum);
00772         long ad = FIX2LONG(aden);
00773         long bn = FIX2LONG(bnum);
00774         long bd = FIX2LONG(bden);
00775         long g1 = i_gcd(an, bd);
00776         long g2 = i_gcd(ad, bn);
00777 
00778         num = f_imul(an / g1, bn / g2);
00779         den = f_imul(ad / g2, bd / g1);
00780     }
00781     else {
00782         VALUE g1 = f_gcd(anum, bden);
00783         VALUE g2 = f_gcd(aden, bnum);
00784 
00785         num = f_mul(f_idiv(anum, g1), f_idiv(bnum, g2));
00786         den = f_mul(f_idiv(aden, g2), f_idiv(bden, g1));
00787     }
00788     return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
00789 }
00790 
00791 /*
00792  * call-seq:
00793  *    rat * numeric  ->  numeric_result
00794  *
00795  * Performs multiplication.
00796  *
00797  * For example:
00798  *
00799  *    Rational(2, 3)  * Rational(2, 3)   #=> (4/9)
00800  *    Rational(900)   * Rational(1)      #=> (900/1)
00801  *    Rational(-2, 9) * Rational(-9, 2)  #=> (1/1)
00802  *    Rational(9, 8)  * 4                #=> (9/2)
00803  *    Rational(20, 9) * 9.8              #=> 21.77777777777778
00804  */
00805 static VALUE
00806 nurat_mul(VALUE self, VALUE other)
00807 {
00808     switch (TYPE(other)) {
00809       case T_FIXNUM:
00810       case T_BIGNUM:
00811         {
00812             get_dat1(self);
00813 
00814             return f_muldiv(self,
00815                             dat->num, dat->den,
00816                             other, ONE, '*');
00817         }
00818       case T_FLOAT:
00819         return f_mul(f_to_f(self), other);
00820       case T_RATIONAL:
00821         {
00822             get_dat2(self, other);
00823 
00824             return f_muldiv(self,
00825                             adat->num, adat->den,
00826                             bdat->num, bdat->den, '*');
00827         }
00828       default:
00829         return rb_num_coerce_bin(self, other, '*');
00830     }
00831 }
00832 
00833 /*
00834  * call-seq:
00835  *    rat / numeric     ->  numeric_result
00836  *    rat.quo(numeric)  ->  numeric_result
00837  *
00838  * Performs division.
00839  *
00840  * For example:
00841  *
00842  *    Rational(2, 3)  / Rational(2, 3)   #=> (1/1)
00843  *    Rational(900)   / Rational(1)      #=> (900/1)
00844  *    Rational(-2, 9) / Rational(-9, 2)  #=> (4/81)
00845  *    Rational(9, 8)  / 4                #=> (9/32)
00846  *    Rational(20, 9) / 9.8              #=> 0.22675736961451246
00847  */
00848 static VALUE
00849 nurat_div(VALUE self, VALUE other)
00850 {
00851     switch (TYPE(other)) {
00852       case T_FIXNUM:
00853       case T_BIGNUM:
00854         if (f_zero_p(other))
00855             rb_raise_zerodiv();
00856         {
00857             get_dat1(self);
00858 
00859             return f_muldiv(self,
00860                             dat->num, dat->den,
00861                             other, ONE, '/');
00862         }
00863       case T_FLOAT:
00864         return rb_funcall(f_to_f(self), '/', 1, other);
00865       case T_RATIONAL:
00866         if (f_zero_p(other))
00867             rb_raise_zerodiv();
00868         {
00869             get_dat2(self, other);
00870 
00871             if (f_one_p(self))
00872                 return f_rational_new_no_reduce2(CLASS_OF(self),
00873                                                  bdat->den, bdat->num);
00874 
00875             return f_muldiv(self,
00876                             adat->num, adat->den,
00877                             bdat->num, bdat->den, '/');
00878         }
00879       default:
00880         return rb_num_coerce_bin(self, other, '/');
00881     }
00882 }
00883 
00884 /*
00885  * call-seq:
00886  *    rat.fdiv(numeric)  ->  float
00887  *
00888  * Performs division and returns the value as a float.
00889  *
00890  * For example:
00891  *
00892  *    Rational(2, 3).fdiv(1)       #=> 0.6666666666666666
00893  *    Rational(2, 3).fdiv(0.5)     #=> 1.3333333333333333
00894  *    Rational(2).fdiv(3)          #=> 0.6666666666666666
00895  */
00896 static VALUE
00897 nurat_fdiv(VALUE self, VALUE other)
00898 {
00899     if (f_zero_p(other))
00900         return f_div(self, f_to_f(other));
00901     return f_to_f(f_div(self, other));
00902 }
00903 
00904 /*
00905  * call-seq:
00906  *    rat ** numeric  ->  numeric_result
00907  *
00908  * Performs exponentiation.
00909  *
00910  * For example:
00911  *
00912  *    Rational(2)    ** Rational(3)    #=> (8/1)
00913  *    Rational(10)   ** -2             #=> (1/100)
00914  *    Rational(10)   ** -2.0           #=> 0.01
00915  *    Rational(-4)   ** Rational(1,2)  #=> (1.2246063538223773e-16+2.0i)
00916  *    Rational(1, 2) ** 0              #=> (1/1)
00917  *    Rational(1, 2) ** 0.0            #=> 1.0
00918  */
00919 static VALUE
00920 nurat_expt(VALUE self, VALUE other)
00921 {
00922     if (k_exact_zero_p(other))
00923         return f_rational_new_bang1(CLASS_OF(self), ONE);
00924 
00925     if (k_rational_p(other)) {
00926         get_dat1(other);
00927 
00928         if (f_one_p(dat->den))
00929             other = dat->num; /* c14n */
00930     }
00931 
00932     switch (TYPE(other)) {
00933       case T_FIXNUM:
00934         {
00935             VALUE num, den;
00936 
00937             get_dat1(self);
00938 
00939             switch (FIX2INT(f_cmp(other, ZERO))) {
00940               case 1:
00941                 num = f_expt(dat->num, other);
00942                 den = f_expt(dat->den, other);
00943                 break;
00944               case -1:
00945                 num = f_expt(dat->den, f_negate(other));
00946                 den = f_expt(dat->num, f_negate(other));
00947                 break;
00948               default:
00949                 num = ONE;
00950                 den = ONE;
00951                 break;
00952             }
00953             return f_rational_new2(CLASS_OF(self), num, den);
00954         }
00955       case T_BIGNUM:
00956         rb_warn("in a**b, b may be too big");
00957         /* fall through */
00958       case T_FLOAT:
00959       case T_RATIONAL:
00960         return f_expt(f_to_f(self), other);
00961       default:
00962         return rb_num_coerce_bin(self, other, id_expt);
00963     }
00964 }
00965 
00966 /*
00967  * call-seq:
00968  *    rat <=> numeric  ->  -1, 0, +1 or nil
00969  *
00970  * Performs comparison and returns -1, 0, or +1.
00971  *
00972  * For example:
00973  *
00974  *    Rational(2, 3)  <=> Rational(2, 3)  #=> 0
00975  *    Rational(5)     <=> 5               #=> 0
00976  *    Rational(2,3)   <=> Rational(1,3)   #=> 1
00977  *    Rational(1,3)   <=> 1               #=> -1
00978  *    Rational(1,3)   <=> 0.3             #=> 1
00979  */
00980 static VALUE
00981 nurat_cmp(VALUE self, VALUE other)
00982 {
00983     switch (TYPE(other)) {
00984       case T_FIXNUM:
00985       case T_BIGNUM:
00986         {
00987             get_dat1(self);
00988 
00989             if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1)
00990                 return f_cmp(dat->num, other); /* c14n */
00991             return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
00992         }
00993       case T_FLOAT:
00994         return f_cmp(f_to_f(self), other);
00995       case T_RATIONAL:
00996         {
00997             VALUE num1, num2;
00998 
00999             get_dat2(self, other);
01000 
01001             if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) &&
01002                 FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) {
01003                 num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den));
01004                 num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den));
01005             }
01006             else {
01007                 num1 = f_mul(adat->num, bdat->den);
01008                 num2 = f_mul(bdat->num, adat->den);
01009             }
01010             return f_cmp(f_sub(num1, num2), ZERO);
01011         }
01012       default:
01013         return rb_num_coerce_cmp(self, other, id_cmp);
01014     }
01015 }
01016 
01017 /*
01018  * call-seq:
01019  *    rat == object  ->  true or false
01020  *
01021  * Returns true if rat equals object numerically.
01022  *
01023  * For example:
01024  *
01025  *    Rational(2, 3)  == Rational(2, 3)   #=> true
01026  *    Rational(5)     == 5                #=> true
01027  *    Rational(0)     == 0.0              #=> true
01028  *    Rational('1/3') == 0.33             #=> false
01029  *    Rational('1/2') == '1/2'            #=> false
01030  */
01031 static VALUE
01032 nurat_eqeq_p(VALUE self, VALUE other)
01033 {
01034     switch (TYPE(other)) {
01035       case T_FIXNUM:
01036       case T_BIGNUM:
01037         {
01038             get_dat1(self);
01039 
01040             if (f_zero_p(dat->num) && f_zero_p(other))
01041                 return Qtrue;
01042 
01043             if (!FIXNUM_P(dat->den))
01044                 return Qfalse;
01045             if (FIX2LONG(dat->den) != 1)
01046                 return Qfalse;
01047             if (f_eqeq_p(dat->num, other))
01048                 return Qtrue;
01049             return Qfalse;
01050         }
01051       case T_FLOAT:
01052         return f_eqeq_p(f_to_f(self), other);
01053       case T_RATIONAL:
01054         {
01055             get_dat2(self, other);
01056 
01057             if (f_zero_p(adat->num) && f_zero_p(bdat->num))
01058                 return Qtrue;
01059 
01060             return f_boolcast(f_eqeq_p(adat->num, bdat->num) &&
01061                               f_eqeq_p(adat->den, bdat->den));
01062         }
01063       default:
01064         return f_eqeq_p(other, self);
01065     }
01066 }
01067 
01068 /* :nodoc: */
01069 static VALUE
01070 nurat_coerce(VALUE self, VALUE other)
01071 {
01072     switch (TYPE(other)) {
01073       case T_FIXNUM:
01074       case T_BIGNUM:
01075         return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
01076       case T_FLOAT:
01077         return rb_assoc_new(other, f_to_f(self));
01078       case T_RATIONAL:
01079         return rb_assoc_new(other, self);
01080       case T_COMPLEX:
01081         if (k_exact_zero_p(RCOMPLEX(other)->imag))
01082             return rb_assoc_new(f_rational_new_bang1
01083                                 (CLASS_OF(self), RCOMPLEX(other)->real), self);
01084     }
01085 
01086     rb_raise(rb_eTypeError, "%s can't be coerced into %s",
01087              rb_obj_classname(other), rb_obj_classname(self));
01088     return Qnil;
01089 }
01090 
01091 #if 0
01092 /* :nodoc: */
01093 static VALUE
01094 nurat_idiv(VALUE self, VALUE other)
01095 {
01096     return f_idiv(self, other);
01097 }
01098 
01099 /* :nodoc: */
01100 static VALUE
01101 nurat_quot(VALUE self, VALUE other)
01102 {
01103     return f_truncate(f_div(self, other));
01104 }
01105 
01106 /* :nodoc: */
01107 static VALUE
01108 nurat_quotrem(VALUE self, VALUE other)
01109 {
01110     VALUE val = f_truncate(f_div(self, other));
01111     return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
01112 }
01113 #endif
01114 
01115 #if 0
01116 /* :nodoc: */
01117 static VALUE
01118 nurat_true(VALUE self)
01119 {
01120     return Qtrue;
01121 }
01122 #endif
01123 
01124 static VALUE
01125 nurat_floor(VALUE self)
01126 {
01127     get_dat1(self);
01128     return f_idiv(dat->num, dat->den);
01129 }
01130 
01131 static VALUE
01132 nurat_ceil(VALUE self)
01133 {
01134     get_dat1(self);
01135     return f_negate(f_idiv(f_negate(dat->num), dat->den));
01136 }
01137 
01138 
01139 /*
01140  * call-seq:
01141  *    rat.to_i  ->  integer
01142  *
01143  * Returns the truncated value as an integer.
01144  *
01145  * Equivalent to
01146  *    rat.truncate.
01147  *
01148  * For example:
01149  *
01150  *    Rational(2, 3).to_i   #=> 0
01151  *    Rational(3).to_i      #=> 3
01152  *    Rational(300.6).to_i  #=> 300
01153  *    Rational(98,71).to_i  #=> 1
01154  *    Rational(-30,2).to_i  #=> -15
01155  */
01156 static VALUE
01157 nurat_truncate(VALUE self)
01158 {
01159     get_dat1(self);
01160     if (f_negative_p(dat->num))
01161         return f_negate(f_idiv(f_negate(dat->num), dat->den));
01162     return f_idiv(dat->num, dat->den);
01163 }
01164 
01165 static VALUE
01166 nurat_round(VALUE self)
01167 {
01168     VALUE num, den, neg;
01169 
01170     get_dat1(self);
01171 
01172     num = dat->num;
01173     den = dat->den;
01174     neg = f_negative_p(num);
01175 
01176     if (neg)
01177         num = f_negate(num);
01178 
01179     num = f_add(f_mul(num, TWO), den);
01180     den = f_mul(den, TWO);
01181     num = f_idiv(num, den);
01182 
01183     if (neg)
01184         num = f_negate(num);
01185 
01186     return num;
01187 }
01188 
01189 static VALUE
01190 f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
01191 {
01192     VALUE n, b, s;
01193 
01194     if (argc == 0)
01195         return (*func)(self);
01196 
01197     rb_scan_args(argc, argv, "01", &n);
01198 
01199     if (!k_integer_p(n))
01200         rb_raise(rb_eTypeError, "not an integer");
01201 
01202     b = f_expt(INT2FIX(10), n);
01203     s = f_mul(self, b);
01204 
01205     s = (*func)(s);
01206 
01207     s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b);
01208 
01209     if (f_lt_p(n, ONE))
01210         s = f_to_i(s);
01211 
01212     return s;
01213 }
01214 
01215 /*
01216  * call-seq:
01217  *    rat.floor               ->  integer
01218  *    rat.floor(precision=0)  ->  rational
01219  *
01220  * Returns the truncated value (toward negative infinity).
01221  *
01222  * For example:
01223  *
01224  *    Rational(3).floor      #=> 3
01225  *    Rational(2, 3).floor   #=> 0
01226  *    Rational(-3, 2).floor  #=> -1
01227  *
01228  *           decimal      -  1  2  3 . 4  5  6
01229  *                          ^  ^  ^  ^   ^  ^
01230  *          precision      -3 -2 -1  0  +1 +2
01231  *
01232  *    '%f' % Rational('-123.456').floor(+1)  #=> "-123.500000"
01233  *    '%f' % Rational('-123.456').floor(-1)  #=> "-130.000000"
01234  */
01235 static VALUE
01236 nurat_floor_n(int argc, VALUE *argv, VALUE self)
01237 {
01238     return f_round_common(argc, argv, self, nurat_floor);
01239 }
01240 
01241 /*
01242  * call-seq:
01243  *    rat.ceil               ->  integer
01244  *    rat.ceil(precision=0)  ->  rational
01245  *
01246  * Returns the truncated value (toward positive infinity).
01247  *
01248  * For example:
01249  *
01250  *    Rational(3).ceil      #=> 3
01251  *    Rational(2, 3).ceil   #=> 1
01252  *    Rational(-3, 2).ceil  #=> -1
01253  *
01254  *           decimal      -  1  2  3 . 4  5  6
01255  *                          ^  ^  ^  ^   ^  ^
01256  *          precision      -3 -2 -1  0  +1 +2
01257  *
01258  *    '%f' % Rational('-123.456').ceil(+1)  #=> "-123.400000"
01259  *    '%f' % Rational('-123.456').ceil(-1)  #=> "-120.000000"
01260  */
01261 static VALUE
01262 nurat_ceil_n(int argc, VALUE *argv, VALUE self)
01263 {
01264     return f_round_common(argc, argv, self, nurat_ceil);
01265 }
01266 
01267 /*
01268  * call-seq:
01269  *    rat.truncate               ->  integer
01270  *    rat.truncate(precision=0)  ->  rational
01271  *
01272  * Returns the truncated value (toward zero).
01273  *
01274  * For example:
01275  *
01276  *    Rational(3).truncate      #=> 3
01277  *    Rational(2, 3).truncate   #=> 0
01278  *    Rational(-3, 2).truncate  #=> -1
01279  *
01280  *           decimal      -  1  2  3 . 4  5  6
01281  *                          ^  ^  ^  ^   ^  ^
01282  *          precision      -3 -2 -1  0  +1 +2
01283  *
01284  *    '%f' % Rational('-123.456').truncate(+1)  #=>  "-123.400000"
01285  *    '%f' % Rational('-123.456').truncate(-1)  #=>  "-120.000000"
01286  */
01287 static VALUE
01288 nurat_truncate_n(int argc, VALUE *argv, VALUE self)
01289 {
01290     return f_round_common(argc, argv, self, nurat_truncate);
01291 }
01292 
01293 /*
01294  * call-seq:
01295  *    rat.round               ->  integer
01296  *    rat.round(precision=0)  ->  rational
01297  *
01298  * Returns the truncated value (toward the nearest integer;
01299  * 0.5 => 1; -0.5 => -1).
01300  *
01301  * For example:
01302  *
01303  *    Rational(3).round      #=> 3
01304  *    Rational(2, 3).round   #=> 1
01305  *    Rational(-3, 2).round  #=> -2
01306  *
01307  *           decimal      -  1  2  3 . 4  5  6
01308  *                          ^  ^  ^  ^   ^  ^
01309  *          precision      -3 -2 -1  0  +1 +2
01310  *
01311  *    '%f' % Rational('-123.456').round(+1)  #=> "-123.500000"
01312  *    '%f' % Rational('-123.456').round(-1)  #=> "-120.000000"
01313  */
01314 static VALUE
01315 nurat_round_n(int argc, VALUE *argv, VALUE self)
01316 {
01317     return f_round_common(argc, argv, self, nurat_round);
01318 }
01319 
01320 /*
01321  * call-seq:
01322  *    rat.to_f  ->  float
01323  *
01324  * Return the value as a float.
01325  *
01326  * For example:
01327  *
01328  *    Rational(2).to_f      #=> 2.0
01329  *    Rational(9, 4).to_f   #=> 2.25
01330  *    Rational(-3, 4).to_f  #=> -0.75
01331  *    Rational(20, 3).to_f  #=> 6.666666666666667
01332  */
01333 static VALUE
01334 nurat_to_f(VALUE self)
01335 {
01336     get_dat1(self);
01337     return f_fdiv(dat->num, dat->den);
01338 }
01339 
01340 /*
01341  * call-seq:
01342  *    rat.to_r  ->  self
01343  *
01344  * Returns self.
01345  *
01346  * For example:
01347  *
01348  *    Rational(2).to_r      #=> (2/1)
01349  *    Rational(-8, 6).to_r  #=> (-4/3)
01350  */
01351 static VALUE
01352 nurat_to_r(VALUE self)
01353 {
01354     return self;
01355 }
01356 
01357 #define id_ceil rb_intern("ceil")
01358 #define f_ceil(x) rb_funcall(x, id_ceil, 0)
01359 
01360 #define id_quo rb_intern("quo")
01361 #define f_quo(x,y) rb_funcall(x, id_quo, 1, y)
01362 
01363 #define f_reciprocal(x) f_quo(ONE, x)
01364 
01365 /*
01366   The algorithm here is the method described in CLISP.  Bruno Haible has
01367   graciously given permission to use this algorithm.  He says, "You can use
01368   it, if you present the following explanation of the algorithm."
01369 
01370   Algorithm (recursively presented):
01371     If x is a rational number, return x.
01372     If x = 0.0, return 0.
01373     If x < 0.0, return (- (rationalize (- x))).
01374     If x > 0.0:
01375       Call (integer-decode-float x). It returns a m,e,s=1 (mantissa,
01376       exponent, sign).
01377       If m = 0 or e >= 0: return x = m*2^e.
01378       Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e
01379       with smallest possible numerator and denominator.
01380       Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e.
01381         But in this case the result will be x itself anyway, regardless of
01382         the choice of a. Therefore we can simply ignore this case.
01383       Note 2: At first, we need to consider the closed interval [a,b].
01384         but since a and b have the denominator 2^(|e|+1) whereas x itself
01385         has a denominator <= 2^|e|, we can restrict the search to the open
01386         interval (a,b).
01387       So, for given a and b (0 < a < b) we are searching a rational number
01388       y with a <= y <= b.
01389       Recursive algorithm fraction_between(a,b):
01390         c := (ceiling a)
01391         if c < b
01392           then return c       ; because a <= c < b, c integer
01393           else
01394             ; a is not integer (otherwise we would have had c = a < b)
01395             k := c-1          ; k = floor(a), k < a < b <= k+1
01396             return y = k + 1/fraction_between(1/(b-k), 1/(a-k))
01397                               ; note 1 <= 1/(b-k) < 1/(a-k)
01398 
01399   You can see that we are actually computing a continued fraction expansion.
01400 
01401   Algorithm (iterative):
01402     If x is rational, return x.
01403     Call (integer-decode-float x). It returns a m,e,s (mantissa,
01404       exponent, sign).
01405     If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.)
01406     Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1)
01407     (positive and already in lowest terms because the denominator is a
01408     power of two and the numerator is odd).
01409     Start a continued fraction expansion
01410       p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0.
01411     Loop
01412       c := (ceiling a)
01413       if c >= b
01414         then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
01415              goto Loop
01416     finally partial_quotient(c).
01417     Here partial_quotient(c) denotes the iteration
01418       i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2].
01419     At the end, return s * (p[i]/q[i]).
01420     This rational number is already in lowest terms because
01421     p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i.
01422 */
01423 
01424 static void
01425 nurat_rationalize_internal(VALUE a, VALUE b, VALUE *p, VALUE *q)
01426 {
01427     VALUE c, k, t, p0, p1, p2, q0, q1, q2;
01428 
01429     p0 = ZERO;
01430     p1 = ONE;
01431     q0 = ONE;
01432     q1 = ZERO;
01433 
01434     while (1) {
01435         c = f_ceil(a);
01436         if (f_lt_p(c, b))
01437             break;
01438         k = f_sub(c, ONE);
01439         p2 = f_add(f_mul(k, p1), p0);
01440         q2 = f_add(f_mul(k, q1), q0);
01441         t = f_reciprocal(f_sub(b, k));
01442         b = f_reciprocal(f_sub(a, k));
01443         a = t;
01444         p0 = p1;
01445         q0 = q1;
01446         p1 = p2;
01447         q1 = q2;
01448     }
01449     *p = f_add(f_mul(c, p1), p0);
01450     *q = f_add(f_mul(c, q1), q0);
01451 }
01452 
01453 /*
01454  * call-seq:
01455  *    rat.rationalize       ->  self
01456  *    rat.rationalize(eps)  ->  rational
01457  *
01458  * Returns a simpler approximation of the value if an optional
01459  * argument eps is given (rat-|eps| <= result <= rat+|eps|), self
01460  * otherwise.
01461  *
01462  * For example:
01463  *
01464  *    r = Rational(5033165, 16777216)
01465  *    r.rationalize                    #=> (5033165/16777216)
01466  *    r.rationalize(Rational('0.01'))  #=> (3/10)
01467  *    r.rationalize(Rational('0.1'))   #=> (1/3)
01468  */
01469 static VALUE
01470 nurat_rationalize(int argc, VALUE *argv, VALUE self)
01471 {
01472     VALUE e, a, b, p, q;
01473 
01474     if (argc == 0)
01475         return self;
01476 
01477     if (f_negative_p(self))
01478         return f_negate(nurat_rationalize(argc, argv, f_abs(self)));
01479 
01480     rb_scan_args(argc, argv, "01", &e);
01481     e = f_abs(e);
01482     a = f_sub(self, e);
01483     b = f_add(self, e);
01484 
01485     if (f_eqeq_p(a, b))
01486         return self;
01487 
01488     nurat_rationalize_internal(a, b, &p, &q);
01489     return f_rational_new2(CLASS_OF(self), p, q);
01490 }
01491 
01492 /* :nodoc: */
01493 static VALUE
01494 nurat_hash(VALUE self)
01495 {
01496     st_index_t v, h[2];
01497     VALUE n;
01498 
01499     get_dat1(self);
01500     n = rb_hash(dat->num);
01501     h[0] = NUM2LONG(n);
01502     n = rb_hash(dat->den);
01503     h[1] = NUM2LONG(n);
01504     v = rb_memhash(h, sizeof(h));
01505     return LONG2FIX(v);
01506 }
01507 
01508 static VALUE
01509 f_format(VALUE self, VALUE (*func)(VALUE))
01510 {
01511     VALUE s;
01512     get_dat1(self);
01513 
01514     s = (*func)(dat->num);
01515     rb_str_cat2(s, "/");
01516     rb_str_concat(s, (*func)(dat->den));
01517 
01518     return s;
01519 }
01520 
01521 /*
01522  * call-seq:
01523  *    rat.to_s  ->  string
01524  *
01525  * Returns the value as a string.
01526  *
01527  * For example:
01528  *
01529  *    Rational(2).to_s      #=> "2/1"
01530  *    Rational(-8, 6).to_s  #=> "-4/3"
01531  *    Rational('0.5').to_s  #=> "1/2"
01532  */
01533 static VALUE
01534 nurat_to_s(VALUE self)
01535 {
01536     return f_format(self, f_to_s);
01537 }
01538 
01539 /*
01540  * call-seq:
01541  *    rat.inspect  ->  string
01542  *
01543  * Returns the value as a string for inspection.
01544  *
01545  * For example:
01546  *
01547  *    Rational(2).inspect      #=> "(2/1)"
01548  *    Rational(-8, 6).inspect  #=> "(-4/3)"
01549  *    Rational('0.5').inspect  #=> "(1/2)"
01550  */
01551 static VALUE
01552 nurat_inspect(VALUE self)
01553 {
01554     VALUE s;
01555 
01556     s = rb_usascii_str_new2("(");
01557     rb_str_concat(s, f_format(self, f_inspect));
01558     rb_str_cat2(s, ")");
01559 
01560     return s;
01561 }
01562 
01563 /* :nodoc: */
01564 static VALUE
01565 nurat_marshal_dump(VALUE self)
01566 {
01567     VALUE a;
01568     get_dat1(self);
01569 
01570     a = rb_assoc_new(dat->num, dat->den);
01571     rb_copy_generic_ivar(a, self);
01572     return a;
01573 }
01574 
01575 /* :nodoc: */
01576 static VALUE
01577 nurat_marshal_load(VALUE self, VALUE a)
01578 {
01579     get_dat1(self);
01580     Check_Type(a, T_ARRAY);
01581     dat->num = RARRAY_PTR(a)[0];
01582     dat->den = RARRAY_PTR(a)[1];
01583     rb_copy_generic_ivar(self, a);
01584 
01585     if (f_zero_p(dat->den))
01586         rb_raise_zerodiv();
01587 
01588     return self;
01589 }
01590 
01591 /* --- */
01592 
01593 VALUE
01594 rb_rational_reciprocal(VALUE x)
01595 {
01596     get_dat1(x);
01597     return f_rational_new_no_reduce2(CLASS_OF(x), dat->den, dat->num);
01598 }
01599 
01600 /*
01601  * call-seq:
01602  *    int.gcd(int2)  ->  integer
01603  *
01604  * Returns the greatest common divisor (always positive).  0.gcd(x)
01605  * and x.gcd(0) return abs(x).
01606  *
01607  * For example:
01608  *
01609  *    2.gcd(2)                    #=> 2
01610  *    3.gcd(-7)                   #=> 1
01611  *    ((1<<31)-1).gcd((1<<61)-1)  #=> 1
01612  */
01613 VALUE
01614 rb_gcd(VALUE self, VALUE other)
01615 {
01616     other = nurat_int_value(other);
01617     return f_gcd(self, other);
01618 }
01619 
01620 /*
01621  * call-seq:
01622  *    int.lcm(int2)  ->  integer
01623  *
01624  * Returns the least common multiple (always positive).  0.lcm(x) and
01625  * x.lcm(0) return zero.
01626  *
01627  * For example:
01628  *
01629  *    2.lcm(2)                    #=> 2
01630  *    3.lcm(-7)                   #=> 21
01631  *    ((1<<31)-1).lcm((1<<61)-1)  #=> 4951760154835678088235319297
01632  */
01633 VALUE
01634 rb_lcm(VALUE self, VALUE other)
01635 {
01636     other = nurat_int_value(other);
01637     return f_lcm(self, other);
01638 }
01639 
01640 /*
01641  * call-seq:
01642  *    int.gcdlcm(int2)  ->  array
01643  *
01644  * Returns an array; [int.gcd(int2), int.lcm(int2)].
01645  *
01646  * For example:
01647  *
01648  *    2.gcdlcm(2)                    #=> [2, 2]
01649  *    3.gcdlcm(-7)                   #=> [1, 21]
01650  *    ((1<<31)-1).gcdlcm((1<<61)-1)  #=> [1, 4951760154835678088235319297]
01651  */
01652 VALUE
01653 rb_gcdlcm(VALUE self, VALUE other)
01654 {
01655     other = nurat_int_value(other);
01656     return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
01657 }
01658 
01659 VALUE
01660 rb_rational_raw(VALUE x, VALUE y)
01661 {
01662     return nurat_s_new_internal(rb_cRational, x, y);
01663 }
01664 
01665 VALUE
01666 rb_rational_new(VALUE x, VALUE y)
01667 {
01668     return nurat_s_canonicalize_internal(rb_cRational, x, y);
01669 }
01670 
01671 static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
01672 
01673 VALUE
01674 rb_Rational(VALUE x, VALUE y)
01675 {
01676     VALUE a[2];
01677     a[0] = x;
01678     a[1] = y;
01679     return nurat_s_convert(2, a, rb_cRational);
01680 }
01681 
01682 #define id_numerator rb_intern("numerator")
01683 #define f_numerator(x) rb_funcall(x, id_numerator, 0)
01684 
01685 #define id_denominator rb_intern("denominator")
01686 #define f_denominator(x) rb_funcall(x, id_denominator, 0)
01687 
01688 #define id_to_r rb_intern("to_r")
01689 #define f_to_r(x) rb_funcall(x, id_to_r, 0)
01690 
01691 /*
01692  * call-seq:
01693  *    num.numerator  ->  integer
01694  *
01695  * Returns the numerator.
01696  */
01697 static VALUE
01698 numeric_numerator(VALUE self)
01699 {
01700     return f_numerator(f_to_r(self));
01701 }
01702 
01703 /*
01704  * call-seq:
01705  *    num.denominator  ->  integer
01706  *
01707  * Returns the denominator (always positive).
01708  */
01709 static VALUE
01710 numeric_denominator(VALUE self)
01711 {
01712     return f_denominator(f_to_r(self));
01713 }
01714 
01715 /*
01716  * call-seq:
01717  *    int.numerator  ->  self
01718  *
01719  * Returns self.
01720  */
01721 static VALUE
01722 integer_numerator(VALUE self)
01723 {
01724     return self;
01725 }
01726 
01727 /*
01728  * call-seq:
01729  *    int.denominator  ->  1
01730  *
01731  * Returns 1.
01732  */
01733 static VALUE
01734 integer_denominator(VALUE self)
01735 {
01736     return INT2FIX(1);
01737 }
01738 
01739 /*
01740  * call-seq:
01741  *    flo.numerator  ->  integer
01742  *
01743  * Returns the numerator.  The result is machine dependent.
01744  *
01745  * For example:
01746  *
01747  *    n = 0.3.numerator    #=> 5404319552844595
01748  *    d = 0.3.denominator  #=> 18014398509481984
01749  *    n.fdiv(d)            #=> 0.3
01750  */
01751 static VALUE
01752 float_numerator(VALUE self)
01753 {
01754     double d = RFLOAT_VALUE(self);
01755     if (isinf(d) || isnan(d))
01756         return self;
01757     return rb_call_super(0, 0);
01758 }
01759 
01760 /*
01761  * call-seq:
01762  *    flo.denominator  ->  integer
01763  *
01764  * Returns the denominator (always positive).  The result is machine
01765  * dependent.
01766  *
01767  * See numerator.
01768  */
01769 static VALUE
01770 float_denominator(VALUE self)
01771 {
01772     double d = RFLOAT_VALUE(self);
01773     if (isinf(d) || isnan(d))
01774         return INT2FIX(1);
01775     return rb_call_super(0, 0);
01776 }
01777 
01778 /*
01779  * call-seq:
01780  *    nil.to_r  ->  (0/1)
01781  *
01782  * Returns zero as a rational.
01783  */
01784 static VALUE
01785 nilclass_to_r(VALUE self)
01786 {
01787     return rb_rational_new1(INT2FIX(0));
01788 }
01789 
01790 /*
01791  * call-seq:
01792  *    nil.rationalize([eps])  ->  (0/1)
01793  *
01794  * Returns zero as a rational.  An optional argument eps is always
01795  * ignored.
01796  */
01797 static VALUE
01798 nilclass_rationalize(int argc, VALUE *argv, VALUE self)
01799 {
01800     rb_scan_args(argc, argv, "01", NULL);
01801     return nilclass_to_r(self);
01802 }
01803 
01804 /*
01805  * call-seq:
01806  *    int.to_r  ->  rational
01807  *
01808  * Returns the value as a rational.
01809  *
01810  * For example:
01811  *
01812  *    1.to_r        #=> (1/1)
01813  *    (1<<64).to_r  #=> (18446744073709551616/1)
01814  */
01815 static VALUE
01816 integer_to_r(VALUE self)
01817 {
01818     return rb_rational_new1(self);
01819 }
01820 
01821 /*
01822  * call-seq:
01823  *    int.rationalize([eps])  ->  rational
01824  *
01825  * Returns the value as a rational.  An optional argument eps is
01826  * always ignored.
01827  */
01828 static VALUE
01829 integer_rationalize(int argc, VALUE *argv, VALUE self)
01830 {
01831     rb_scan_args(argc, argv, "01", NULL);
01832     return integer_to_r(self);
01833 }
01834 
01835 static void
01836 float_decode_internal(VALUE self, VALUE *rf, VALUE *rn)
01837 {
01838     double f;
01839     int n;
01840 
01841     f = frexp(RFLOAT_VALUE(self), &n);
01842     f = ldexp(f, DBL_MANT_DIG);
01843     n -= DBL_MANT_DIG;
01844     *rf = rb_dbl2big(f);
01845     *rn = INT2FIX(n);
01846 }
01847 
01848 #if 0
01849 static VALUE
01850 float_decode(VALUE self)
01851 {
01852     VALUE f, n;
01853 
01854     float_decode_internal(self, &f, &n);
01855     return rb_assoc_new(f, n);
01856 }
01857 #endif
01858 
01859 #define id_lshift rb_intern("<<")
01860 #define f_lshift(x,n) rb_funcall(x, id_lshift, 1, n)
01861 
01862 /*
01863  * call-seq:
01864  *    flt.to_r  ->  rational
01865  *
01866  * Returns the value as a rational.
01867  *
01868  * NOTE: 0.3.to_r isn't the same as '0.3'.to_r.  The latter is
01869  * equivalent to '3/10'.to_r, but the former isn't so.
01870  *
01871  * For example:
01872  *
01873  *    2.0.to_r    #=> (2/1)
01874  *    2.5.to_r    #=> (5/2)
01875  *    -0.75.to_r  #=> (-3/4)
01876  *    0.0.to_r    #=> (0/1)
01877  */
01878 static VALUE
01879 float_to_r(VALUE self)
01880 {
01881     VALUE f, n;
01882 
01883     float_decode_internal(self, &f, &n);
01884 #if FLT_RADIX == 2
01885     {
01886         long ln = FIX2LONG(n);
01887 
01888         if (ln == 0)
01889             return f_to_r(f);
01890         if (ln > 0)
01891             return f_to_r(f_lshift(f, n));
01892         ln = -ln;
01893         return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln)));
01894     }
01895 #else
01896     return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n)));
01897 #endif
01898 }
01899 
01900 /*
01901  * call-seq:
01902  *    flt.rationalize([eps])  ->  rational
01903  *
01904  * Returns a simpler approximation of the value (flt-|eps| <= result
01905  * <= flt+|eps|).  if eps is not given, it will be chosen
01906  * automatically.
01907  *
01908  * For example:
01909  *
01910  *    0.3.rationalize          #=> (3/10)
01911  *    1.333.rationalize        #=> (1333/1000)
01912  *    1.333.rationalize(0.01)  #=> (4/3)
01913  */
01914 static VALUE
01915 float_rationalize(int argc, VALUE *argv, VALUE self)
01916 {
01917     VALUE e, a, b, p, q;
01918 
01919     if (f_negative_p(self))
01920         return f_negate(float_rationalize(argc, argv, f_abs(self)));
01921 
01922     rb_scan_args(argc, argv, "01", &e);
01923 
01924     if (argc != 0) {
01925         e = f_abs(e);
01926         a = f_sub(self, e);
01927         b = f_add(self, e);
01928     }
01929     else {
01930         VALUE f, n;
01931 
01932         float_decode_internal(self, &f, &n);
01933         if (f_zero_p(f) || f_positive_p(n))
01934             return rb_rational_new1(f_lshift(f, n));
01935 
01936 #if FLT_RADIX == 2
01937         a = rb_rational_new2(f_sub(f_mul(TWO, f), ONE),
01938                              f_lshift(ONE, f_sub(ONE, n)));
01939         b = rb_rational_new2(f_add(f_mul(TWO, f), ONE),
01940                              f_lshift(ONE, f_sub(ONE, n)));
01941 #else
01942         a = rb_rational_new2(f_sub(f_mul(INT2FIX(FLT_RADIX), f),
01943                                    INT2FIX(FLT_RADIX - 1)),
01944                              f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n)));
01945         b = rb_rational_new2(f_add(f_mul(INT2FIX(FLT_RADIX), f),
01946                                    INT2FIX(FLT_RADIX - 1)),
01947                              f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n)));
01948 #endif
01949     }
01950 
01951     if (f_eqeq_p(a, b))
01952         return f_to_r(self);
01953 
01954     nurat_rationalize_internal(a, b, &p, &q);
01955     return rb_rational_new2(p, q);
01956 }
01957 
01958 static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
01959 
01960 #define WS "\\s*"
01961 #define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
01962 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
01963 #define DENOMINATOR DIGITS
01964 #define PATTERN "\\A" WS "([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?" WS
01965 
01966 static void
01967 make_patterns(void)
01968 {
01969     static const char rat_pat_source[] = PATTERN;
01970     static const char an_e_pat_source[] = "[eE]";
01971     static const char a_dot_pat_source[] = "\\.";
01972     static const char underscores_pat_source[] = "_+";
01973 
01974     if (rat_pat) return;
01975 
01976     rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
01977     rb_gc_register_mark_object(rat_pat);
01978 
01979     an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
01980     rb_gc_register_mark_object(an_e_pat);
01981 
01982     a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
01983     rb_gc_register_mark_object(a_dot_pat);
01984 
01985     underscores_pat = rb_reg_new(underscores_pat_source,
01986                                  sizeof underscores_pat_source - 1, 0);
01987     rb_gc_register_mark_object(underscores_pat);
01988 
01989     an_underscore = rb_usascii_str_new2("_");
01990     rb_gc_register_mark_object(an_underscore);
01991 }
01992 
01993 #define id_match rb_intern("match")
01994 #define f_match(x,y) rb_funcall(x, id_match, 1, y)
01995 
01996 #define id_aref rb_intern("[]")
01997 #define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
01998 
01999 #define id_post_match rb_intern("post_match")
02000 #define f_post_match(x) rb_funcall(x, id_post_match, 0)
02001 
02002 #define id_split rb_intern("split")
02003 #define f_split(x,y) rb_funcall(x, id_split, 1, y)
02004 
02005 #include <ctype.h>
02006 
02007 static VALUE
02008 string_to_r_internal(VALUE self)
02009 {
02010     VALUE s, m;
02011 
02012     s = self;
02013 
02014     if (RSTRING_LEN(s) == 0)
02015         return rb_assoc_new(Qnil, self);
02016 
02017     m = f_match(rat_pat, s);
02018 
02019     if (!NIL_P(m)) {
02020         VALUE v, ifp, exp, ip, fp;
02021         VALUE si = f_aref(m, INT2FIX(1));
02022         VALUE nu = f_aref(m, INT2FIX(2));
02023         VALUE de = f_aref(m, INT2FIX(3));
02024         VALUE re = f_post_match(m);
02025 
02026         {
02027             VALUE a;
02028 
02029             a = f_split(nu, an_e_pat);
02030             ifp = RARRAY_PTR(a)[0];
02031             if (RARRAY_LEN(a) != 2)
02032                 exp = Qnil;
02033             else
02034                 exp = RARRAY_PTR(a)[1];
02035 
02036             a = f_split(ifp, a_dot_pat);
02037             ip = RARRAY_PTR(a)[0];
02038             if (RARRAY_LEN(a) != 2)
02039                 fp = Qnil;
02040             else
02041                 fp = RARRAY_PTR(a)[1];
02042         }
02043 
02044         v = rb_rational_new1(f_to_i(ip));
02045 
02046         if (!NIL_P(fp)) {
02047             char *p = StringValuePtr(fp);
02048             long count = 0;
02049             VALUE l;
02050 
02051             while (*p) {
02052                 if (rb_isdigit(*p))
02053                     count++;
02054                 p++;
02055             }
02056 
02057             l = f_expt(INT2FIX(10), LONG2NUM(count));
02058             v = f_mul(v, l);
02059             v = f_add(v, f_to_i(fp));
02060             v = f_div(v, l);
02061         }
02062         if (!NIL_P(si) && *StringValuePtr(si) == '-')
02063             v = f_negate(v);
02064         if (!NIL_P(exp))
02065             v = f_mul(v, f_expt(INT2FIX(10), f_to_i(exp)));
02066 #if 0
02067         if (!NIL_P(de) && (!NIL_P(fp) || !NIL_P(exp)))
02068             return rb_assoc_new(v, rb_usascii_str_new2("dummy"));
02069 #endif
02070         if (!NIL_P(de))
02071             v = f_div(v, f_to_i(de));
02072 
02073         return rb_assoc_new(v, re);
02074     }
02075     return rb_assoc_new(Qnil, self);
02076 }
02077 
02078 static VALUE
02079 string_to_r_strict(VALUE self)
02080 {
02081     VALUE a = string_to_r_internal(self);
02082     if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
02083         VALUE s = f_inspect(self);
02084         rb_raise(rb_eArgError, "invalid value for convert(): %s",
02085                  StringValuePtr(s));
02086     }
02087     return RARRAY_PTR(a)[0];
02088 }
02089 
02090 #define id_gsub rb_intern("gsub")
02091 #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
02092 
02093 /*
02094  * call-seq:
02095  *    str.to_r  ->  rational
02096  *
02097  * Returns a rational which denotes the string form.  The parser
02098  * ignores leading whitespaces and trailing garbage.  Any digit
02099  * sequences can be separated by an underscore.  Returns zero for null
02100  * or garbage string.
02101  *
02102  * NOTE: '0.3'.to_r isn't the same as 0.3.to_r.  The former is
02103  * equivalent to '3/10'.to_r, but the latter isn't so.
02104  *
02105  * For example:
02106  *
02107  *    '  2  '.to_r       #=> (2/1)
02108  *    '300/2'.to_r       #=> (150/1)
02109  *    '-9.2'.to_r        #=> (-46/5)
02110  *    '-9.2e2'.to_r      #=> (-920/1)
02111  *    '1_234_567'.to_r   #=> (1234567/1)
02112  *    '21 june 09'.to_r  #=> (21/1)
02113  *    '21/06/09'.to_r    #=> (7/2)
02114  *    'bwv 1079'.to_r    #=> (0/1)
02115  */
02116 static VALUE
02117 string_to_r(VALUE self)
02118 {
02119     VALUE s, a, backref;
02120 
02121     backref = rb_backref_get();
02122     rb_match_busy(backref);
02123 
02124     s = f_gsub(self, underscores_pat, an_underscore);
02125     a = string_to_r_internal(s);
02126 
02127     rb_backref_set(backref);
02128 
02129     if (!NIL_P(RARRAY_PTR(a)[0]))
02130         return RARRAY_PTR(a)[0];
02131     return rb_rational_new1(INT2FIX(0));
02132 }
02133 
02134 #define id_to_r rb_intern("to_r")
02135 #define f_to_r(x) rb_funcall(x, id_to_r, 0)
02136 
02137 static VALUE
02138 nurat_s_convert(int argc, VALUE *argv, VALUE klass)
02139 {
02140     VALUE a1, a2, backref;
02141 
02142     rb_scan_args(argc, argv, "11", &a1, &a2);
02143 
02144     if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
02145         rb_raise(rb_eTypeError, "can't convert nil into Rational");
02146 
02147     switch (TYPE(a1)) {
02148       case T_COMPLEX:
02149         if (k_exact_zero_p(RCOMPLEX(a1)->imag))
02150             a1 = RCOMPLEX(a1)->real;
02151     }
02152 
02153     switch (TYPE(a2)) {
02154       case T_COMPLEX:
02155         if (k_exact_zero_p(RCOMPLEX(a2)->imag))
02156             a2 = RCOMPLEX(a2)->real;
02157     }
02158 
02159     backref = rb_backref_get();
02160     rb_match_busy(backref);
02161 
02162     switch (TYPE(a1)) {
02163       case T_FIXNUM:
02164       case T_BIGNUM:
02165         break;
02166       case T_FLOAT:
02167         a1 = f_to_r(a1);
02168         break;
02169       case T_STRING:
02170         a1 = string_to_r_strict(a1);
02171         break;
02172     }
02173 
02174     switch (TYPE(a2)) {
02175       case T_FIXNUM:
02176       case T_BIGNUM:
02177         break;
02178       case T_FLOAT:
02179         a2 = f_to_r(a2);
02180         break;
02181       case T_STRING:
02182         a2 = string_to_r_strict(a2);
02183         break;
02184     }
02185 
02186     rb_backref_set(backref);
02187 
02188     switch (TYPE(a1)) {
02189       case T_RATIONAL:
02190         if (argc == 1 || (k_exact_one_p(a2)))
02191             return a1;
02192     }
02193 
02194     if (argc == 1) {
02195         if (!(k_numeric_p(a1) && k_integer_p(a1)))
02196             return rb_convert_type(a1, T_RATIONAL, "Rational", "to_r");
02197     }
02198     else {
02199         if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
02200             (!f_integer_p(a1) || !f_integer_p(a2)))
02201             return f_div(a1, a2);
02202     }
02203 
02204     {
02205         VALUE argv2[2];
02206         argv2[0] = a1;
02207         argv2[1] = a2;
02208         return nurat_s_new(argc, argv2, klass);
02209     }
02210 }
02211 
02212 /*
02213  * A rational number can be represented as a paired integer number;
02214  * a/b (b>0).  Where a is numerator and b is denominator.  Integer a
02215  * equals rational a/1 mathematically.
02216  *
02217  * In ruby, you can create rational object with Rational or to_r
02218  * method.  The return values will be irreducible.
02219  *
02220  *    Rational(1)      #=> (1/1)
02221  *    Rational(2, 3)   #=> (2/3)
02222  *    Rational(4, -6)  #=> (-2/3)
02223  *    3.to_r           #=> (3/1)
02224  *
02225  * You can also create rational object from floating-point numbers or
02226  * strings.
02227  *
02228  *    Rational(0.3)    #=> (5404319552844595/18014398509481984)
02229  *    Rational('0.3')  #=> (3/10)
02230  *    Rational('2/3')  #=> (2/3)
02231  *
02232  *    0.3.to_r         #=> (5404319552844595/18014398509481984)
02233  *    '0.3'.to_r       #=> (3/10)
02234  *    '2/3'.to_r       #=> (2/3)
02235  *
02236  * A rational object is an exact number, which helps you to write
02237  * program without any rounding errors.
02238  *
02239  *    10.times.inject(0){|t,| t + 0.1}              #=> 0.9999999999999999
02240  *    10.times.inject(0){|t,| t + Rational('0.1')}  #=> (1/1)
02241  *
02242  * However, when an expression has inexact factor (numerical value or
02243  * operation), will produce an inexact result.
02244  *
02245  *    Rational(10) / 3   #=> (10/3)
02246  *    Rational(10) / 3.0 #=> 3.3333333333333335
02247  *
02248  *    Rational(-8) ** Rational(1, 3)
02249  *                       #=> (1.0000000000000002+1.7320508075688772i)
02250  */
02251 void
02252 Init_Rational(void)
02253 {
02254 #undef rb_intern
02255 #define rb_intern(str) rb_intern_const(str)
02256 
02257     assert(fprintf(stderr, "assert() is now active\n"));
02258 
02259     id_abs = rb_intern("abs");
02260     id_cmp = rb_intern("<=>");
02261     id_convert = rb_intern("convert");
02262     id_eqeq_p = rb_intern("==");
02263     id_expt = rb_intern("**");
02264     id_fdiv = rb_intern("fdiv");
02265     id_floor = rb_intern("floor");
02266     id_idiv = rb_intern("div");
02267     id_inspect = rb_intern("inspect");
02268     id_integer_p = rb_intern("integer?");
02269     id_negate = rb_intern("-@");
02270     id_to_f = rb_intern("to_f");
02271     id_to_i = rb_intern("to_i");
02272     id_to_s = rb_intern("to_s");
02273     id_truncate = rb_intern("truncate");
02274 
02275     rb_cRational = rb_define_class("Rational", rb_cNumeric);
02276 
02277     rb_define_alloc_func(rb_cRational, nurat_s_alloc);
02278     rb_undef_method(CLASS_OF(rb_cRational), "allocate");
02279 
02280 #if 0
02281     rb_define_private_method(CLASS_OF(rb_cRational), "new!", nurat_s_new_bang, -1);
02282     rb_define_private_method(CLASS_OF(rb_cRational), "new", nurat_s_new, -1);
02283 #else
02284     rb_undef_method(CLASS_OF(rb_cRational), "new");
02285 #endif
02286 
02287     rb_define_global_function("Rational", nurat_f_rational, -1);
02288 
02289     rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
02290     rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
02291 
02292     rb_define_method(rb_cRational, "+", nurat_add, 1);
02293     rb_define_method(rb_cRational, "-", nurat_sub, 1);
02294     rb_define_method(rb_cRational, "*", nurat_mul, 1);
02295     rb_define_method(rb_cRational, "/", nurat_div, 1);
02296     rb_define_method(rb_cRational, "quo", nurat_div, 1);
02297     rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
02298     rb_define_method(rb_cRational, "**", nurat_expt, 1);
02299 
02300     rb_define_method(rb_cRational, "<=>", nurat_cmp, 1);
02301     rb_define_method(rb_cRational, "==", nurat_eqeq_p, 1);
02302     rb_define_method(rb_cRational, "coerce", nurat_coerce, 1);
02303 
02304 #if 0 /* NUBY */
02305     rb_define_method(rb_cRational, "//", nurat_idiv, 1);
02306 #endif
02307 
02308 #if 0
02309     rb_define_method(rb_cRational, "quot", nurat_quot, 1);
02310     rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1);
02311 #endif
02312 
02313 #if 0
02314     rb_define_method(rb_cRational, "rational?", nurat_true, 0);
02315     rb_define_method(rb_cRational, "exact?", nurat_true, 0);
02316 #endif
02317 
02318     rb_define_method(rb_cRational, "floor", nurat_floor_n, -1);
02319     rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1);
02320     rb_define_method(rb_cRational, "truncate", nurat_truncate_n, -1);
02321     rb_define_method(rb_cRational, "round", nurat_round_n, -1);
02322 
02323     rb_define_method(rb_cRational, "to_i", nurat_truncate, 0);
02324     rb_define_method(rb_cRational, "to_f", nurat_to_f, 0);
02325     rb_define_method(rb_cRational, "to_r", nurat_to_r, 0);
02326     rb_define_method(rb_cRational, "rationalize", nurat_rationalize, -1);
02327 
02328     rb_define_method(rb_cRational, "hash", nurat_hash, 0);
02329 
02330     rb_define_method(rb_cRational, "to_s", nurat_to_s, 0);
02331     rb_define_method(rb_cRational, "inspect", nurat_inspect, 0);
02332 
02333     rb_define_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
02334     rb_define_method(rb_cRational, "marshal_load", nurat_marshal_load, 1);
02335 
02336     /* --- */
02337 
02338     rb_define_method(rb_cInteger, "gcd", rb_gcd, 1);
02339     rb_define_method(rb_cInteger, "lcm", rb_lcm, 1);
02340     rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1);
02341 
02342     rb_define_method(rb_cNumeric, "numerator", numeric_numerator, 0);
02343     rb_define_method(rb_cNumeric, "denominator", numeric_denominator, 0);
02344 
02345     rb_define_method(rb_cInteger, "numerator", integer_numerator, 0);
02346     rb_define_method(rb_cInteger, "denominator", integer_denominator, 0);
02347 
02348     rb_define_method(rb_cFloat, "numerator", float_numerator, 0);
02349     rb_define_method(rb_cFloat, "denominator", float_denominator, 0);
02350 
02351     rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
02352     rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1);
02353     rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
02354     rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1);
02355     rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
02356     rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1);
02357 
02358     make_patterns();
02359 
02360     rb_define_method(rb_cString, "to_r", string_to_r, 0);
02361 
02362     rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1);
02363 }
02364 
02365 /*
02366 Local variables:
02367 c-file-style: "ruby"
02368 End:
02369 */
02370 

Generated on Wed Sep 8 2010 09:55:07 for Ruby by  doxygen 1.7.1