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