Ruby 1.9.2p136(2010-12-25revision30365)

- 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