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
00605
00606 static VALUE
00607 nurat_f_rational(int argc, VALUE *argv, VALUE klass)
00608 {
00609 return rb_funcall2(rb_cRational, id_convert, argc, argv);
00610 }
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 static VALUE
00624 nurat_numerator(VALUE self)
00625 {
00626 get_dat1(self);
00627 return dat->num;
00628 }
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 static VALUE
00643 nurat_denominator(VALUE self)
00644 {
00645 get_dat1(self);
00646 return dat->den;
00647 }
00648
00649 #ifndef NDEBUG
00650 #define f_imul f_imul_orig
00651 #endif
00652
00653 inline static VALUE
00654 f_imul(long a, long b)
00655 {
00656 VALUE r;
00657
00658 if (a == 0 || b == 0)
00659 return ZERO;
00660 else if (a == 1)
00661 return LONG2NUM(b);
00662 else if (b == 1)
00663 return LONG2NUM(a);
00664
00665 if (MUL_OVERFLOW_LONG_P(a, b))
00666 r = rb_big_mul(rb_int2big(a), rb_int2big(b));
00667 else
00668 r = LONG2NUM(a * b);
00669 return r;
00670 }
00671
00672 #ifndef NDEBUG
00673 #undef f_imul
00674
00675 inline static VALUE
00676 f_imul(long x, long y)
00677 {
00678 VALUE r = f_imul_orig(x, y);
00679 assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
00680 return r;
00681 }
00682 #endif
00683
00684 inline static VALUE
00685 f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
00686 {
00687 VALUE num, den;
00688
00689 if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
00690 FIXNUM_P(bnum) && FIXNUM_P(bden)) {
00691 long an = FIX2LONG(anum);
00692 long ad = FIX2LONG(aden);
00693 long bn = FIX2LONG(bnum);
00694 long bd = FIX2LONG(bden);
00695 long ig = i_gcd(ad, bd);
00696
00697 VALUE g = LONG2NUM(ig);
00698 VALUE a = f_imul(an, bd / ig);
00699 VALUE b = f_imul(bn, ad / ig);
00700 VALUE c;
00701
00702 if (k == '+')
00703 c = f_add(a, b);
00704 else
00705 c = f_sub(a, b);
00706
00707 b = f_idiv(aden, g);
00708 g = f_gcd(c, g);
00709 num = f_idiv(c, g);
00710 a = f_idiv(bden, g);
00711 den = f_mul(a, b);
00712 }
00713 else {
00714 VALUE g = f_gcd(aden, bden);
00715 VALUE a = f_mul(anum, f_idiv(bden, g));
00716 VALUE b = f_mul(bnum, f_idiv(aden, g));
00717 VALUE c;
00718
00719 if (k == '+')
00720 c = f_add(a, b);
00721 else
00722 c = f_sub(a, b);
00723
00724 b = f_idiv(aden, g);
00725 g = f_gcd(c, g);
00726 num = f_idiv(c, g);
00727 a = f_idiv(bden, g);
00728 den = f_mul(a, b);
00729 }
00730 return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
00731 }
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 static VALUE
00746 nurat_add(VALUE self, VALUE other)
00747 {
00748 if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
00749 {
00750 get_dat1(self);
00751
00752 return f_addsub(self,
00753 dat->num, dat->den,
00754 other, ONE, '+');
00755 }
00756 }
00757 else if (RB_TYPE_P(other, T_FLOAT)) {
00758 return f_add(f_to_f(self), other);
00759 }
00760 else if (RB_TYPE_P(other, T_RATIONAL)) {
00761 {
00762 get_dat2(self, other);
00763
00764 return f_addsub(self,
00765 adat->num, adat->den,
00766 bdat->num, bdat->den, '+');
00767 }
00768 }
00769 else {
00770 return rb_num_coerce_bin(self, other, '+');
00771 }
00772 }
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 static VALUE
00787 nurat_sub(VALUE self, VALUE other)
00788 {
00789 if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
00790 {
00791 get_dat1(self);
00792
00793 return f_addsub(self,
00794 dat->num, dat->den,
00795 other, ONE, '-');
00796 }
00797 }
00798 else if (RB_TYPE_P(other, T_FLOAT)) {
00799 return f_sub(f_to_f(self), other);
00800 }
00801 else if (RB_TYPE_P(other, T_RATIONAL)) {
00802 {
00803 get_dat2(self, other);
00804
00805 return f_addsub(self,
00806 adat->num, adat->den,
00807 bdat->num, bdat->den, '-');
00808 }
00809 }
00810 else {
00811 return rb_num_coerce_bin(self, other, '-');
00812 }
00813 }
00814
00815 inline static VALUE
00816 f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
00817 {
00818 VALUE num, den;
00819
00820 if (k == '/') {
00821 VALUE t;
00822
00823 if (f_negative_p(bnum)) {
00824 anum = f_negate(anum);
00825 bnum = f_negate(bnum);
00826 }
00827 t = bnum;
00828 bnum = bden;
00829 bden = t;
00830 }
00831
00832 if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
00833 FIXNUM_P(bnum) && FIXNUM_P(bden)) {
00834 long an = FIX2LONG(anum);
00835 long ad = FIX2LONG(aden);
00836 long bn = FIX2LONG(bnum);
00837 long bd = FIX2LONG(bden);
00838 long g1 = i_gcd(an, bd);
00839 long g2 = i_gcd(ad, bn);
00840
00841 num = f_imul(an / g1, bn / g2);
00842 den = f_imul(ad / g2, bd / g1);
00843 }
00844 else {
00845 VALUE g1 = f_gcd(anum, bden);
00846 VALUE g2 = f_gcd(aden, bnum);
00847
00848 num = f_mul(f_idiv(anum, g1), f_idiv(bnum, g2));
00849 den = f_mul(f_idiv(aden, g2), f_idiv(bden, g1));
00850 }
00851 return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
00852 }
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866 static VALUE
00867 nurat_mul(VALUE self, VALUE other)
00868 {
00869 if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
00870 {
00871 get_dat1(self);
00872
00873 return f_muldiv(self,
00874 dat->num, dat->den,
00875 other, ONE, '*');
00876 }
00877 }
00878 else if (RB_TYPE_P(other, T_FLOAT)) {
00879 return f_mul(f_to_f(self), other);
00880 }
00881 else if (RB_TYPE_P(other, T_RATIONAL)) {
00882 {
00883 get_dat2(self, other);
00884
00885 return f_muldiv(self,
00886 adat->num, adat->den,
00887 bdat->num, bdat->den, '*');
00888 }
00889 }
00890 else {
00891 return rb_num_coerce_bin(self, other, '*');
00892 }
00893 }
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908 static VALUE
00909 nurat_div(VALUE self, VALUE other)
00910 {
00911 if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
00912 if (f_zero_p(other))
00913 rb_raise_zerodiv();
00914 {
00915 get_dat1(self);
00916
00917 return f_muldiv(self,
00918 dat->num, dat->den,
00919 other, ONE, '/');
00920 }
00921 }
00922 else if (RB_TYPE_P(other, T_FLOAT))
00923 return rb_funcall(f_to_f(self), '/', 1, other);
00924 else if (RB_TYPE_P(other, T_RATIONAL)) {
00925 if (f_zero_p(other))
00926 rb_raise_zerodiv();
00927 {
00928 get_dat2(self, other);
00929
00930 if (f_one_p(self))
00931 return f_rational_new_no_reduce2(CLASS_OF(self),
00932 bdat->den, bdat->num);
00933
00934 return f_muldiv(self,
00935 adat->num, adat->den,
00936 bdat->num, bdat->den, '/');
00937 }
00938 }
00939 else {
00940 return rb_num_coerce_bin(self, other, '/');
00941 }
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 static VALUE
00955 nurat_fdiv(VALUE self, VALUE other)
00956 {
00957 if (f_zero_p(other))
00958 return f_div(self, f_to_f(other));
00959 return f_to_f(f_div(self, other));
00960 }
00961
00962 inline static VALUE
00963 f_odd_p(VALUE integer)
00964 {
00965 if (rb_funcall(integer, '%', 1, INT2FIX(2)) != INT2FIX(0)) {
00966 return Qtrue;
00967 }
00968 return Qfalse;
00969 }
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984 static VALUE
00985 nurat_expt(VALUE self, VALUE other)
00986 {
00987 if (k_numeric_p(other) && k_exact_zero_p(other))
00988 return f_rational_new_bang1(CLASS_OF(self), ONE);
00989
00990 if (k_rational_p(other)) {
00991 get_dat1(other);
00992
00993 if (f_one_p(dat->den))
00994 other = dat->num;
00995 }
00996
00997
00998 if (k_numeric_p(other) && k_exact_p(other)) {
00999 get_dat1(self);
01000 if (f_one_p(dat->den)) {
01001 if (f_one_p(dat->num)) {
01002 return f_rational_new_bang1(CLASS_OF(self), ONE);
01003 }
01004 else if (f_minus_one_p(dat->num) && k_integer_p(other)) {
01005 return f_rational_new_bang1(CLASS_OF(self), INT2FIX(f_odd_p(other) ? -1 : 1));
01006 }
01007 else if (f_zero_p(dat->num)) {
01008 if (FIX2INT(f_cmp(other, ZERO)) == -1) {
01009 rb_raise_zerodiv();
01010 }
01011 else {
01012 return f_rational_new_bang1(CLASS_OF(self), ZERO);
01013 }
01014 }
01015 }
01016 }
01017
01018
01019 if (RB_TYPE_P(other, T_FIXNUM)) {
01020 {
01021 VALUE num, den;
01022
01023 get_dat1(self);
01024
01025 switch (FIX2INT(f_cmp(other, ZERO))) {
01026 case 1:
01027 num = f_expt(dat->num, other);
01028 den = f_expt(dat->den, other);
01029 break;
01030 case -1:
01031 num = f_expt(dat->den, f_negate(other));
01032 den = f_expt(dat->num, f_negate(other));
01033 break;
01034 default:
01035 num = ONE;
01036 den = ONE;
01037 break;
01038 }
01039 return f_rational_new2(CLASS_OF(self), num, den);
01040 }
01041 }
01042 else if (RB_TYPE_P(other, T_BIGNUM)) {
01043 rb_warn("in a**b, b may be too big");
01044 return f_expt(f_to_f(self), other);
01045 }
01046 else if (RB_TYPE_P(other, T_FLOAT) || RB_TYPE_P(other, T_RATIONAL)) {
01047 return f_expt(f_to_f(self), other);
01048 }
01049 else {
01050 return rb_num_coerce_bin(self, other, id_expt);
01051 }
01052 }
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068 static VALUE
01069 nurat_cmp(VALUE self, VALUE other)
01070 {
01071 if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
01072 {
01073 get_dat1(self);
01074
01075 if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1)
01076 return f_cmp(dat->num, other);
01077 return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
01078 }
01079 }
01080 else if (RB_TYPE_P(other, T_FLOAT)) {
01081 return f_cmp(f_to_f(self), other);
01082 }
01083 else if (RB_TYPE_P(other, T_RATIONAL)) {
01084 {
01085 VALUE num1, num2;
01086
01087 get_dat2(self, other);
01088
01089 if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) &&
01090 FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) {
01091 num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den));
01092 num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den));
01093 }
01094 else {
01095 num1 = f_mul(adat->num, bdat->den);
01096 num2 = f_mul(bdat->num, adat->den);
01097 }
01098 return f_cmp(f_sub(num1, num2), ZERO);
01099 }
01100 }
01101 else {
01102 return rb_num_coerce_cmp(self, other, id_cmp);
01103 }
01104 }
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118 static VALUE
01119 nurat_eqeq_p(VALUE self, VALUE other)
01120 {
01121 if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
01122 {
01123 get_dat1(self);
01124
01125 if (f_zero_p(dat->num) && f_zero_p(other))
01126 return Qtrue;
01127
01128 if (!FIXNUM_P(dat->den))
01129 return Qfalse;
01130 if (FIX2LONG(dat->den) != 1)
01131 return Qfalse;
01132 if (f_eqeq_p(dat->num, other))
01133 return Qtrue;
01134 return Qfalse;
01135 }
01136 }
01137 else if (RB_TYPE_P(other, T_FLOAT)) {
01138 return f_eqeq_p(f_to_f(self), other);
01139 }
01140 else if (RB_TYPE_P(other, T_RATIONAL)) {
01141 {
01142 get_dat2(self, other);
01143
01144 if (f_zero_p(adat->num) && f_zero_p(bdat->num))
01145 return Qtrue;
01146
01147 return f_boolcast(f_eqeq_p(adat->num, bdat->num) &&
01148 f_eqeq_p(adat->den, bdat->den));
01149 }
01150 }
01151 else {
01152 return f_eqeq_p(other, self);
01153 }
01154 }
01155
01156
01157 static VALUE
01158 nurat_coerce(VALUE self, VALUE other)
01159 {
01160 if (RB_TYPE_P(other, T_FIXNUM) || RB_TYPE_P(other, T_BIGNUM)) {
01161 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
01162 }
01163 else if (RB_TYPE_P(other, T_FLOAT)) {
01164 return rb_assoc_new(other, f_to_f(self));
01165 }
01166 else if (RB_TYPE_P(other, T_RATIONAL)) {
01167 return rb_assoc_new(other, self);
01168 }
01169 else if (RB_TYPE_P(other, T_COMPLEX)) {
01170 if (k_exact_zero_p(RCOMPLEX(other)->imag))
01171 return rb_assoc_new(f_rational_new_bang1
01172 (CLASS_OF(self), RCOMPLEX(other)->real), self);
01173 else
01174 return rb_assoc_new(other, rb_Complex(self, INT2FIX(0)));
01175 }
01176
01177 rb_raise(rb_eTypeError, "%s can't be coerced into %s",
01178 rb_obj_classname(other), rb_obj_classname(self));
01179 return Qnil;
01180 }
01181
01182 #if 0
01183
01184 static VALUE
01185 nurat_idiv(VALUE self, VALUE other)
01186 {
01187 return f_idiv(self, other);
01188 }
01189
01190
01191 static VALUE
01192 nurat_quot(VALUE self, VALUE other)
01193 {
01194 return f_truncate(f_div(self, other));
01195 }
01196
01197
01198 static VALUE
01199 nurat_quotrem(VALUE self, VALUE other)
01200 {
01201 VALUE val = f_truncate(f_div(self, other));
01202 return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
01203 }
01204 #endif
01205
01206 #if 0
01207
01208 static VALUE
01209 nurat_true(VALUE self)
01210 {
01211 return Qtrue;
01212 }
01213 #endif
01214
01215 static VALUE
01216 nurat_floor(VALUE self)
01217 {
01218 get_dat1(self);
01219 return f_idiv(dat->num, dat->den);
01220 }
01221
01222 static VALUE
01223 nurat_ceil(VALUE self)
01224 {
01225 get_dat1(self);
01226 return f_negate(f_idiv(f_negate(dat->num), dat->den));
01227 }
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244 static VALUE
01245 nurat_truncate(VALUE self)
01246 {
01247 get_dat1(self);
01248 if (f_negative_p(dat->num))
01249 return f_negate(f_idiv(f_negate(dat->num), dat->den));
01250 return f_idiv(dat->num, dat->den);
01251 }
01252
01253 static VALUE
01254 nurat_round(VALUE self)
01255 {
01256 VALUE num, den, neg;
01257
01258 get_dat1(self);
01259
01260 num = dat->num;
01261 den = dat->den;
01262 neg = f_negative_p(num);
01263
01264 if (neg)
01265 num = f_negate(num);
01266
01267 num = f_add(f_mul(num, TWO), den);
01268 den = f_mul(den, TWO);
01269 num = f_idiv(num, den);
01270
01271 if (neg)
01272 num = f_negate(num);
01273
01274 return num;
01275 }
01276
01277 static VALUE
01278 f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
01279 {
01280 VALUE n, b, s;
01281
01282 if (argc == 0)
01283 return (*func)(self);
01284
01285 rb_scan_args(argc, argv, "01", &n);
01286
01287 if (!k_integer_p(n))
01288 rb_raise(rb_eTypeError, "not an integer");
01289
01290 b = f_expt10(n);
01291 s = f_mul(self, b);
01292
01293 if (k_float_p(s)) {
01294 if (f_lt_p(n, ZERO))
01295 return ZERO;
01296 return self;
01297 }
01298
01299 if (!k_rational_p(s)) {
01300 s = f_rational_new_bang1(CLASS_OF(self), s);
01301 }
01302
01303 s = (*func)(s);
01304
01305 s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b);
01306
01307 if (f_lt_p(n, ONE))
01308 s = f_to_i(s);
01309
01310 return s;
01311 }
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331 static VALUE
01332 nurat_floor_n(int argc, VALUE *argv, VALUE self)
01333 {
01334 return f_round_common(argc, argv, self, nurat_floor);
01335 }
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355 static VALUE
01356 nurat_ceil_n(int argc, VALUE *argv, VALUE self)
01357 {
01358 return f_round_common(argc, argv, self, nurat_ceil);
01359 }
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379 static VALUE
01380 nurat_truncate_n(int argc, VALUE *argv, VALUE self)
01381 {
01382 return f_round_common(argc, argv, self, nurat_truncate);
01383 }
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404 static VALUE
01405 nurat_round_n(int argc, VALUE *argv, VALUE self)
01406 {
01407 return f_round_common(argc, argv, self, nurat_round);
01408 }
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421 static VALUE
01422 nurat_to_f(VALUE self)
01423 {
01424 get_dat1(self);
01425 return f_fdiv(dat->num, dat->den);
01426 }
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437 static VALUE
01438 nurat_to_r(VALUE self)
01439 {
01440 return self;
01441 }
01442
01443 #define id_ceil rb_intern("ceil")
01444 #define f_ceil(x) rb_funcall((x), id_ceil, 0)
01445
01446 #define id_quo rb_intern("quo")
01447 #define f_quo(x,y) rb_funcall((x), id_quo, 1, (y))
01448
01449 #define f_reciprocal(x) f_quo(ONE, (x))
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
01509
01510 static void
01511 nurat_rationalize_internal(VALUE a, VALUE b, VALUE *p, VALUE *q)
01512 {
01513 VALUE c, k, t, p0, p1, p2, q0, q1, q2;
01514
01515 p0 = ZERO;
01516 p1 = ONE;
01517 q0 = ONE;
01518 q1 = ZERO;
01519
01520 while (1) {
01521 c = f_ceil(a);
01522 if (f_lt_p(c, b))
01523 break;
01524 k = f_sub(c, ONE);
01525 p2 = f_add(f_mul(k, p1), p0);
01526 q2 = f_add(f_mul(k, q1), q0);
01527 t = f_reciprocal(f_sub(b, k));
01528 b = f_reciprocal(f_sub(a, k));
01529 a = t;
01530 p0 = p1;
01531 q0 = q1;
01532 p1 = p2;
01533 q1 = q2;
01534 }
01535 *p = f_add(f_mul(c, p1), p0);
01536 *q = f_add(f_mul(c, q1), q0);
01537 }
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553 static VALUE
01554 nurat_rationalize(int argc, VALUE *argv, VALUE self)
01555 {
01556 VALUE e, a, b, p, q;
01557
01558 if (argc == 0)
01559 return self;
01560
01561 if (f_negative_p(self))
01562 return f_negate(nurat_rationalize(argc, argv, f_abs(self)));
01563
01564 rb_scan_args(argc, argv, "01", &e);
01565 e = f_abs(e);
01566 a = f_sub(self, e);
01567 b = f_add(self, e);
01568
01569 if (f_eqeq_p(a, b))
01570 return self;
01571
01572 nurat_rationalize_internal(a, b, &p, &q);
01573 return f_rational_new2(CLASS_OF(self), p, q);
01574 }
01575
01576
01577 static VALUE
01578 nurat_hash(VALUE self)
01579 {
01580 st_index_t v, h[2];
01581 VALUE n;
01582
01583 get_dat1(self);
01584 n = rb_hash(dat->num);
01585 h[0] = NUM2LONG(n);
01586 n = rb_hash(dat->den);
01587 h[1] = NUM2LONG(n);
01588 v = rb_memhash(h, sizeof(h));
01589 return LONG2FIX(v);
01590 }
01591
01592 static VALUE
01593 f_format(VALUE self, VALUE (*func)(VALUE))
01594 {
01595 VALUE s;
01596 get_dat1(self);
01597
01598 s = (*func)(dat->num);
01599 rb_str_cat2(s, "/");
01600 rb_str_concat(s, (*func)(dat->den));
01601
01602 return s;
01603 }
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615 static VALUE
01616 nurat_to_s(VALUE self)
01617 {
01618 return f_format(self, f_to_s);
01619 }
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631 static VALUE
01632 nurat_inspect(VALUE self)
01633 {
01634 VALUE s;
01635
01636 s = rb_usascii_str_new2("(");
01637 rb_str_concat(s, f_format(self, f_inspect));
01638 rb_str_cat2(s, ")");
01639
01640 return s;
01641 }
01642
01643
01644 static VALUE
01645 nurat_dumper(VALUE self)
01646 {
01647 return self;
01648 }
01649
01650
01651 static VALUE
01652 nurat_loader(VALUE self, VALUE a)
01653 {
01654 get_dat1(self);
01655
01656 RRATIONAL_SET_NUM(dat, rb_ivar_get(a, id_i_num));
01657 RRATIONAL_SET_DEN(dat, rb_ivar_get(a, id_i_den));
01658
01659 return self;
01660 }
01661
01662
01663 static VALUE
01664 nurat_marshal_dump(VALUE self)
01665 {
01666 VALUE a;
01667 get_dat1(self);
01668
01669 a = rb_assoc_new(dat->num, dat->den);
01670 rb_copy_generic_ivar(a, self);
01671 return a;
01672 }
01673
01674
01675 static VALUE
01676 nurat_marshal_load(VALUE self, VALUE a)
01677 {
01678 rb_check_frozen(self);
01679 rb_check_trusted(self);
01680
01681 Check_Type(a, T_ARRAY);
01682 if (RARRAY_LEN(a) != 2)
01683 rb_raise(rb_eArgError, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a));
01684 if (f_zero_p(RARRAY_AREF(a, 1)))
01685 rb_raise_zerodiv();
01686
01687 rb_ivar_set(self, id_i_num, RARRAY_AREF(a, 0));
01688 rb_ivar_set(self, id_i_den, RARRAY_AREF(a, 1));
01689
01690 return self;
01691 }
01692
01693
01694
01695 VALUE
01696 rb_rational_reciprocal(VALUE x)
01697 {
01698 get_dat1(x);
01699 return f_rational_new_no_reduce2(CLASS_OF(x), dat->den, dat->num);
01700 }
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713 VALUE
01714 rb_gcd(VALUE self, VALUE other)
01715 {
01716 other = nurat_int_value(other);
01717 return f_gcd(self, other);
01718 }
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731 VALUE
01732 rb_lcm(VALUE self, VALUE other)
01733 {
01734 other = nurat_int_value(other);
01735 return f_lcm(self, other);
01736 }
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748 VALUE
01749 rb_gcdlcm(VALUE self, VALUE other)
01750 {
01751 other = nurat_int_value(other);
01752 return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
01753 }
01754
01755 VALUE
01756 rb_rational_raw(VALUE x, VALUE y)
01757 {
01758 return nurat_s_new_internal(rb_cRational, x, y);
01759 }
01760
01761 VALUE
01762 rb_rational_new(VALUE x, VALUE y)
01763 {
01764 return nurat_s_canonicalize_internal(rb_cRational, x, y);
01765 }
01766
01767 static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
01768
01769 VALUE
01770 rb_Rational(VALUE x, VALUE y)
01771 {
01772 VALUE a[2];
01773 a[0] = x;
01774 a[1] = y;
01775 return nurat_s_convert(2, a, rb_cRational);
01776 }
01777
01778 #define id_numerator rb_intern("numerator")
01779 #define f_numerator(x) rb_funcall((x), id_numerator, 0)
01780
01781 #define id_denominator rb_intern("denominator")
01782 #define f_denominator(x) rb_funcall((x), id_denominator, 0)
01783
01784 #define id_to_r rb_intern("to_r")
01785 #define f_to_r(x) rb_funcall((x), id_to_r, 0)
01786
01787
01788
01789
01790
01791
01792
01793 static VALUE
01794 numeric_numerator(VALUE self)
01795 {
01796 return f_numerator(f_to_r(self));
01797 }
01798
01799
01800
01801
01802
01803
01804
01805 static VALUE
01806 numeric_denominator(VALUE self)
01807 {
01808 return f_denominator(f_to_r(self));
01809 }
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820 static VALUE
01821 numeric_quo(VALUE x, VALUE y)
01822 {
01823 if (RB_TYPE_P(y, T_FLOAT)) {
01824 return f_fdiv(x, y);
01825 }
01826
01827 #ifdef CANON
01828 if (canonicalization) {
01829 x = rb_rational_raw1(x);
01830 }
01831 else
01832 #endif
01833 {
01834 x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r");
01835 }
01836 return rb_funcall(x, '/', 1, y);
01837 }
01838
01839
01840
01841
01842
01843
01844
01845
01846 static VALUE
01847 integer_numerator(VALUE self)
01848 {
01849 return self;
01850 }
01851
01852
01853
01854
01855
01856
01857
01858 static VALUE
01859 integer_denominator(VALUE self)
01860 {
01861 return INT2FIX(1);
01862 }
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874 static VALUE
01875 float_numerator(VALUE self)
01876 {
01877 double d = RFLOAT_VALUE(self);
01878 if (isinf(d) || isnan(d))
01879 return self;
01880 return rb_call_super(0, 0);
01881 }
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892 static VALUE
01893 float_denominator(VALUE self)
01894 {
01895 double d = RFLOAT_VALUE(self);
01896 if (isinf(d) || isnan(d))
01897 return INT2FIX(1);
01898 return rb_call_super(0, 0);
01899 }
01900
01901
01902
01903
01904
01905
01906
01907 static VALUE
01908 nilclass_to_r(VALUE self)
01909 {
01910 return rb_rational_new1(INT2FIX(0));
01911 }
01912
01913
01914
01915
01916
01917
01918
01919
01920 static VALUE
01921 nilclass_rationalize(int argc, VALUE *argv, VALUE self)
01922 {
01923 rb_scan_args(argc, argv, "01", NULL);
01924 return nilclass_to_r(self);
01925 }
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936 static VALUE
01937 integer_to_r(VALUE self)
01938 {
01939 return rb_rational_new1(self);
01940 }
01941
01942
01943
01944
01945
01946
01947
01948
01949 static VALUE
01950 integer_rationalize(int argc, VALUE *argv, VALUE self)
01951 {
01952 rb_scan_args(argc, argv, "01", NULL);
01953 return integer_to_r(self);
01954 }
01955
01956 static void
01957 float_decode_internal(VALUE self, VALUE *rf, VALUE *rn)
01958 {
01959 double f;
01960 int n;
01961
01962 f = frexp(RFLOAT_VALUE(self), &n);
01963 f = ldexp(f, DBL_MANT_DIG);
01964 n -= DBL_MANT_DIG;
01965 *rf = rb_dbl2big(f);
01966 *rn = INT2FIX(n);
01967 }
01968
01969 #if 0
01970 static VALUE
01971 float_decode(VALUE self)
01972 {
01973 VALUE f, n;
01974
01975 float_decode_internal(self, &f, &n);
01976 return rb_assoc_new(f, n);
01977 }
01978 #endif
01979
01980 #define id_lshift rb_intern("<<")
01981 #define f_lshift(x,n) rb_funcall((x), id_lshift, 1, (n))
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999 static VALUE
02000 float_to_r(VALUE self)
02001 {
02002 VALUE f, n;
02003
02004 float_decode_internal(self, &f, &n);
02005 #if FLT_RADIX == 2
02006 {
02007 long ln = FIX2LONG(n);
02008
02009 if (ln == 0)
02010 return f_to_r(f);
02011 if (ln > 0)
02012 return f_to_r(f_lshift(f, n));
02013 ln = -ln;
02014 return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln)));
02015 }
02016 #else
02017 return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n)));
02018 #endif
02019 }
02020
02021 VALUE
02022 rb_flt_rationalize_with_prec(VALUE flt, VALUE prec)
02023 {
02024 VALUE e, a, b, p, q;
02025
02026 e = f_abs(prec);
02027 a = f_sub(flt, e);
02028 b = f_add(flt, e);
02029
02030 if (f_eqeq_p(a, b))
02031 return f_to_r(flt);
02032
02033 nurat_rationalize_internal(a, b, &p, &q);
02034 return rb_rational_new2(p, q);
02035 }
02036
02037 VALUE
02038 rb_flt_rationalize(VALUE flt)
02039 {
02040 VALUE a, b, f, n, p, q;
02041
02042 float_decode_internal(flt, &f, &n);
02043 if (f_zero_p(f) || f_positive_p(n))
02044 return rb_rational_new1(f_lshift(f, n));
02045
02046 #if FLT_RADIX == 2
02047 {
02048 VALUE two_times_f, den;
02049
02050 two_times_f = f_mul(TWO, f);
02051 den = f_lshift(ONE, f_sub(ONE, n));
02052
02053 a = rb_rational_new2(f_sub(two_times_f, ONE), den);
02054 b = rb_rational_new2(f_add(two_times_f, ONE), den);
02055 }
02056 #else
02057 {
02058 VALUE radix_times_f, den;
02059
02060 radix_times_f = f_mul(INT2FIX(FLT_RADIX), f);
02061 den = f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n));
02062
02063 a = rb_rational_new2(f_sub(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
02064 b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
02065 }
02066 #endif
02067
02068 if (f_eqeq_p(a, b))
02069 return f_to_r(flt);
02070
02071 nurat_rationalize_internal(a, b, &p, &q);
02072 return rb_rational_new2(p, q);
02073 }
02074
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089 static VALUE
02090 float_rationalize(int argc, VALUE *argv, VALUE self)
02091 {
02092 VALUE e;
02093
02094 if (f_negative_p(self))
02095 return f_negate(float_rationalize(argc, argv, f_abs(self)));
02096
02097 rb_scan_args(argc, argv, "01", &e);
02098
02099 if (argc != 0) {
02100 return rb_flt_rationalize_with_prec(self, e);
02101 }
02102 else {
02103 return rb_flt_rationalize(self);
02104 }
02105 }
02106
02107 #include <ctype.h>
02108
02109 inline static int
02110 issign(int c)
02111 {
02112 return (c == '-' || c == '+');
02113 }
02114
02115 static int
02116 read_sign(const char **s)
02117 {
02118 int sign = '?';
02119
02120 if (issign(**s)) {
02121 sign = **s;
02122 (*s)++;
02123 }
02124 return sign;
02125 }
02126
02127 inline static int
02128 isdecimal(int c)
02129 {
02130 return isdigit((unsigned char)c);
02131 }
02132
02133 static int
02134 read_digits(const char **s, int strict,
02135 VALUE *num, int *count)
02136 {
02137 char *b, *bb;
02138 int us = 1, ret = 1;
02139 VALUE tmp;
02140
02141 if (!isdecimal(**s)) {
02142 *num = ZERO;
02143 return 0;
02144 }
02145
02146 bb = b = ALLOCV_N(char, tmp, strlen(*s) + 1);
02147
02148 while (isdecimal(**s) || **s == '_') {
02149 if (**s == '_') {
02150 if (strict) {
02151 if (us) {
02152 ret = 0;
02153 goto conv;
02154 }
02155 }
02156 us = 1;
02157 }
02158 else {
02159 if (count)
02160 (*count)++;
02161 *b++ = **s;
02162 us = 0;
02163 }
02164 (*s)++;
02165 }
02166 if (us)
02167 do {
02168 (*s)--;
02169 } while (**s == '_');
02170 conv:
02171 *b = '\0';
02172 *num = rb_cstr_to_inum(bb, 10, 0);
02173 ALLOCV_END(tmp);
02174 return ret;
02175 }
02176
02177 inline static int
02178 islettere(int c)
02179 {
02180 return (c == 'e' || c == 'E');
02181 }
02182
02183 static int
02184 read_num(const char **s, int numsign, int strict,
02185 VALUE *num)
02186 {
02187 VALUE ip, fp, exp;
02188
02189 *num = rb_rational_new2(ZERO, ONE);
02190 exp = Qnil;
02191
02192 if (**s != '.') {
02193 if (!read_digits(s, strict, &ip, NULL))
02194 return 0;
02195 *num = rb_rational_new2(ip, ONE);
02196 }
02197
02198 if (**s == '.') {
02199 int count = 0;
02200
02201 (*s)++;
02202 if (!read_digits(s, strict, &fp, &count))
02203 return 0;
02204 {
02205 VALUE l = f_expt10(INT2NUM(count));
02206 *num = f_mul(*num, l);
02207 *num = f_add(*num, fp);
02208 *num = f_div(*num, l);
02209 }
02210 }
02211
02212 if (islettere(**s)) {
02213 int expsign;
02214
02215 (*s)++;
02216 expsign = read_sign(s);
02217 if (!read_digits(s, strict, &exp, NULL))
02218 return 0;
02219 if (expsign == '-')
02220 exp = f_negate(exp);
02221 }
02222
02223 if (numsign == '-')
02224 *num = f_negate(*num);
02225 if (!NIL_P(exp)) {
02226 VALUE l = f_expt10(exp);
02227 *num = f_mul(*num, l);
02228 }
02229 return 1;
02230 }
02231
02232 inline static int
02233 read_den(const char **s, int strict,
02234 VALUE *num)
02235 {
02236 if (!read_digits(s, strict, num, NULL))
02237 return 0;
02238 return 1;
02239 }
02240
02241 static int
02242 read_rat_nos(const char **s, int sign, int strict,
02243 VALUE *num)
02244 {
02245 VALUE den;
02246
02247 if (!read_num(s, sign, strict, num))
02248 return 0;
02249 if (**s == '/') {
02250 (*s)++;
02251 if (!read_den(s, strict, &den))
02252 return 0;
02253 if (!(FIXNUM_P(den) && FIX2LONG(den) == 1))
02254 *num = f_div(*num, den);
02255 }
02256 return 1;
02257 }
02258
02259 static int
02260 read_rat(const char **s, int strict,
02261 VALUE *num)
02262 {
02263 int sign;
02264
02265 sign = read_sign(s);
02266 if (!read_rat_nos(s, sign, strict, num))
02267 return 0;
02268 return 1;
02269 }
02270
02271 inline static void
02272 skip_ws(const char **s)
02273 {
02274 while (isspace((unsigned char)**s))
02275 (*s)++;
02276 }
02277
02278 static int
02279 parse_rat(const char *s, int strict,
02280 VALUE *num)
02281 {
02282 skip_ws(&s);
02283 if (!read_rat(&s, strict, num))
02284 return 0;
02285 skip_ws(&s);
02286
02287 if (strict)
02288 if (*s != '\0')
02289 return 0;
02290 return 1;
02291 }
02292
02293 static VALUE
02294 string_to_r_strict(VALUE self)
02295 {
02296 char *s;
02297 VALUE num;
02298
02299 rb_must_asciicompat(self);
02300
02301 s = RSTRING_PTR(self);
02302
02303 if (!s || memchr(s, '\0', RSTRING_LEN(self)))
02304 rb_raise(rb_eArgError, "string contains null byte");
02305
02306 if (s && s[RSTRING_LEN(self)]) {
02307 rb_str_modify(self);
02308 s = RSTRING_PTR(self);
02309 s[RSTRING_LEN(self)] = '\0';
02310 }
02311
02312 if (!s)
02313 s = (char *)"";
02314
02315 if (!parse_rat(s, 1, &num)) {
02316 VALUE ins = f_inspect(self);
02317 rb_raise(rb_eArgError, "invalid value for convert(): %s",
02318 StringValuePtr(ins));
02319 }
02320
02321 if (RB_TYPE_P(num, T_FLOAT))
02322 rb_raise(rb_eFloatDomainError, "Infinity");
02323 return num;
02324 }
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349 static VALUE
02350 string_to_r(VALUE self)
02351 {
02352 char *s;
02353 VALUE num;
02354
02355 rb_must_asciicompat(self);
02356
02357 s = RSTRING_PTR(self);
02358
02359 if (s && s[RSTRING_LEN(self)]) {
02360 rb_str_modify(self);
02361 s = RSTRING_PTR(self);
02362 s[RSTRING_LEN(self)] = '\0';
02363 }
02364
02365 if (!s)
02366 s = (char *)"";
02367
02368 (void)parse_rat(s, 0, &num);
02369
02370 if (RB_TYPE_P(num, T_FLOAT))
02371 rb_raise(rb_eFloatDomainError, "Infinity");
02372 return num;
02373 }
02374
02375 VALUE
02376 rb_cstr_to_rat(const char *s, int strict)
02377 {
02378 VALUE num;
02379
02380 (void)parse_rat(s, strict, &num);
02381
02382 if (RB_TYPE_P(num, T_FLOAT))
02383 rb_raise(rb_eFloatDomainError, "Infinity");
02384 return num;
02385 }
02386
02387 static VALUE
02388 nurat_s_convert(int argc, VALUE *argv, VALUE klass)
02389 {
02390 VALUE a1, a2, backref;
02391
02392 rb_scan_args(argc, argv, "11", &a1, &a2);
02393
02394 if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
02395 rb_raise(rb_eTypeError, "can't convert nil into Rational");
02396
02397 if (RB_TYPE_P(a1, T_COMPLEX)) {
02398 if (k_exact_zero_p(RCOMPLEX(a1)->imag))
02399 a1 = RCOMPLEX(a1)->real;
02400 }
02401
02402 if (RB_TYPE_P(a2, T_COMPLEX)) {
02403 if (k_exact_zero_p(RCOMPLEX(a2)->imag))
02404 a2 = RCOMPLEX(a2)->real;
02405 }
02406
02407 backref = rb_backref_get();
02408 rb_match_busy(backref);
02409
02410 if (RB_TYPE_P(a1, T_FLOAT)) {
02411 a1 = f_to_r(a1);
02412 }
02413 else if (RB_TYPE_P(a1, T_STRING)) {
02414 a1 = string_to_r_strict(a1);
02415 }
02416
02417 if (RB_TYPE_P(a2, T_FLOAT)) {
02418 a2 = f_to_r(a2);
02419 }
02420 else if (RB_TYPE_P(a2, T_STRING)) {
02421 a2 = string_to_r_strict(a2);
02422 }
02423
02424 rb_backref_set(backref);
02425
02426 if (RB_TYPE_P(a1, T_RATIONAL)) {
02427 if (argc == 1 || (k_exact_one_p(a2)))
02428 return a1;
02429 }
02430
02431 if (argc == 1) {
02432 if (!(k_numeric_p(a1) && k_integer_p(a1)))
02433 return rb_convert_type(a1, T_RATIONAL, "Rational", "to_r");
02434 }
02435 else {
02436 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
02437 (!f_integer_p(a1) || !f_integer_p(a2)))
02438 return f_div(a1, a2);
02439 }
02440
02441 {
02442 VALUE argv2[2];
02443 argv2[0] = a1;
02444 argv2[1] = a2;
02445 return nurat_s_new(argc, argv2, klass);
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
02488
02489
02490 void
02491 Init_Rational(void)
02492 {
02493 VALUE compat;
02494 #undef rb_intern
02495 #define rb_intern(str) rb_intern_const(str)
02496
02497 assert(fprintf(stderr, "assert() is now active\n"));
02498
02499 id_abs = rb_intern("abs");
02500 id_cmp = rb_intern("<=>");
02501 id_convert = rb_intern("convert");
02502 id_eqeq_p = rb_intern("==");
02503 id_expt = rb_intern("**");
02504 id_fdiv = rb_intern("fdiv");
02505 id_idiv = rb_intern("div");
02506 id_integer_p = rb_intern("integer?");
02507 id_negate = rb_intern("-@");
02508 id_to_f = rb_intern("to_f");
02509 id_to_i = rb_intern("to_i");
02510 id_truncate = rb_intern("truncate");
02511 id_i_num = rb_intern("@numerator");
02512 id_i_den = rb_intern("@denominator");
02513
02514 rb_cRational = rb_define_class("Rational", rb_cNumeric);
02515
02516 rb_define_alloc_func(rb_cRational, nurat_s_alloc);
02517 rb_undef_method(CLASS_OF(rb_cRational), "allocate");
02518
02519 #if 0
02520 rb_define_private_method(CLASS_OF(rb_cRational), "new!", nurat_s_new_bang, -1);
02521 rb_define_private_method(CLASS_OF(rb_cRational), "new", nurat_s_new, -1);
02522 #else
02523 rb_undef_method(CLASS_OF(rb_cRational), "new");
02524 #endif
02525
02526 rb_define_global_function("Rational", nurat_f_rational, -1);
02527
02528 rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
02529 rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
02530
02531 rb_define_method(rb_cRational, "+", nurat_add, 1);
02532 rb_define_method(rb_cRational, "-", nurat_sub, 1);
02533 rb_define_method(rb_cRational, "*", nurat_mul, 1);
02534 rb_define_method(rb_cRational, "/", nurat_div, 1);
02535 rb_define_method(rb_cRational, "quo", nurat_div, 1);
02536 rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
02537 rb_define_method(rb_cRational, "**", nurat_expt, 1);
02538
02539 rb_define_method(rb_cRational, "<=>", nurat_cmp, 1);
02540 rb_define_method(rb_cRational, "==", nurat_eqeq_p, 1);
02541 rb_define_method(rb_cRational, "coerce", nurat_coerce, 1);
02542
02543 #if 0
02544 rb_define_method(rb_cRational, "//", nurat_idiv, 1);
02545 #endif
02546
02547 #if 0
02548 rb_define_method(rb_cRational, "quot", nurat_quot, 1);
02549 rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1);
02550 #endif
02551
02552 #if 0
02553 rb_define_method(rb_cRational, "rational?", nurat_true, 0);
02554 rb_define_method(rb_cRational, "exact?", nurat_true, 0);
02555 #endif
02556
02557 rb_define_method(rb_cRational, "floor", nurat_floor_n, -1);
02558 rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1);
02559 rb_define_method(rb_cRational, "truncate", nurat_truncate_n, -1);
02560 rb_define_method(rb_cRational, "round", nurat_round_n, -1);
02561
02562 rb_define_method(rb_cRational, "to_i", nurat_truncate, 0);
02563 rb_define_method(rb_cRational, "to_f", nurat_to_f, 0);
02564 rb_define_method(rb_cRational, "to_r", nurat_to_r, 0);
02565 rb_define_method(rb_cRational, "rationalize", nurat_rationalize, -1);
02566
02567 rb_define_method(rb_cRational, "hash", nurat_hash, 0);
02568
02569 rb_define_method(rb_cRational, "to_s", nurat_to_s, 0);
02570 rb_define_method(rb_cRational, "inspect", nurat_inspect, 0);
02571
02572 rb_define_private_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
02573 compat = rb_define_class_under(rb_cRational, "compatible", rb_cObject);
02574 rb_define_private_method(compat, "marshal_load", nurat_marshal_load, 1);
02575 rb_marshal_define_compat(rb_cRational, compat, nurat_dumper, nurat_loader);
02576
02577
02578
02579 rb_define_method(rb_cInteger, "gcd", rb_gcd, 1);
02580 rb_define_method(rb_cInteger, "lcm", rb_lcm, 1);
02581 rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1);
02582
02583 rb_define_method(rb_cNumeric, "numerator", numeric_numerator, 0);
02584 rb_define_method(rb_cNumeric, "denominator", numeric_denominator, 0);
02585 rb_define_method(rb_cNumeric, "quo", numeric_quo, 1);
02586
02587 rb_define_method(rb_cInteger, "numerator", integer_numerator, 0);
02588 rb_define_method(rb_cInteger, "denominator", integer_denominator, 0);
02589
02590 rb_define_method(rb_cFloat, "numerator", float_numerator, 0);
02591 rb_define_method(rb_cFloat, "denominator", float_denominator, 0);
02592
02593 rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
02594 rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1);
02595 rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
02596 rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1);
02597 rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
02598 rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1);
02599
02600 rb_define_method(rb_cString, "to_r", string_to_r, 0);
02601
02602 rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1);
02603 }
02604
02605
02606
02607
02608
02609
02610