rational.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7