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