00001
00002
00003
00004
00005
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
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
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
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
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621 static VALUE
00622 nurat_numerator(VALUE self)
00623 {
00624 get_dat1(self);
00625 return dat->num;
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
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
00733
00734
00735
00736
00737
00738
00739
00740
00741
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
00774
00775
00776
00777
00778
00779
00780
00781
00782
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
00854
00855
00856
00857
00858
00859
00860
00861
00862
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
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
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
00944
00945
00946
00947
00948
00949
00950
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
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
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;
00993 }
00994
00995
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
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
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
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);
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
01106
01107
01108
01109
01110
01111
01112
01113
01114
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
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
01182 static VALUE
01183 nurat_idiv(VALUE self, VALUE other)
01184 {
01185 return f_idiv(self, other);
01186 }
01187
01188
01189 static VALUE
01190 nurat_quot(VALUE self, VALUE other)
01191 {
01192 return f_truncate(f_div(self, other));
01193 }
01194
01195
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
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
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
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
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
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
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
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
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
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
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
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
01410
01411
01412
01413
01414
01415
01416
01417
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
01428
01429
01430
01431
01432
01433
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
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
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
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
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
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
01605
01606
01607
01608
01609
01610
01611
01612
01613 static VALUE
01614 nurat_to_s(VALUE self)
01615 {
01616 return f_format(self, f_to_s);
01617 }
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
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
01642 static VALUE
01643 nurat_dumper(VALUE self)
01644 {
01645 return self;
01646 }
01647
01648
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
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
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
01702
01703
01704
01705
01706
01707
01708
01709
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
01720
01721
01722
01723
01724
01725
01726
01727
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
01738
01739
01740
01741
01742
01743
01744
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
01787
01788
01789
01790
01791 static VALUE
01792 numeric_numerator(VALUE self)
01793 {
01794 return f_numerator(f_to_r(self));
01795 }
01796
01797
01798
01799
01800
01801
01802
01803 static VALUE
01804 numeric_denominator(VALUE self)
01805 {
01806 return f_denominator(f_to_r(self));
01807 }
01808
01809
01810
01811
01812
01813
01814
01815
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
01840
01841
01842
01843
01844 static VALUE
01845 integer_numerator(VALUE self)
01846 {
01847 return self;
01848 }
01849
01850
01851
01852
01853
01854
01855
01856 static VALUE
01857 integer_denominator(VALUE self)
01858 {
01859 return INT2FIX(1);
01860 }
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
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
01883
01884
01885
01886
01887
01888
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
01901
01902
01903
01904
01905 static VALUE
01906 nilclass_to_r(VALUE self)
01907 {
01908 return rb_rational_new1(INT2FIX(0));
01909 }
01910
01911
01912
01913
01914
01915
01916
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
01927
01928
01929
01930
01931
01932
01933
01934 static VALUE
01935 integer_to_r(VALUE self)
01936 {
01937 return rb_rational_new1(self);
01938 }
01939
01940
01941
01942
01943
01944
01945
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
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
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
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
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
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
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)
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
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
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
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
02604
02605
02606
02607