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 if (!k_rational_p(s)) {
01234 s = f_rational_new_bang1(CLASS_OF(self), s);
01235 }
01236
01237 s = (*func)(s);
01238
01239 s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b);
01240
01241 if (f_lt_p(n, ONE))
01242 s = f_to_i(s);
01243
01244 return s;
01245 }
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267 static VALUE
01268 nurat_floor_n(int argc, VALUE *argv, VALUE self)
01269 {
01270 return f_round_common(argc, argv, self, nurat_floor);
01271 }
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293 static VALUE
01294 nurat_ceil_n(int argc, VALUE *argv, VALUE self)
01295 {
01296 return f_round_common(argc, argv, self, nurat_ceil);
01297 }
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319 static VALUE
01320 nurat_truncate_n(int argc, VALUE *argv, VALUE self)
01321 {
01322 return f_round_common(argc, argv, self, nurat_truncate);
01323 }
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346 static VALUE
01347 nurat_round_n(int argc, VALUE *argv, VALUE self)
01348 {
01349 return f_round_common(argc, argv, self, nurat_round);
01350 }
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365 static VALUE
01366 nurat_to_f(VALUE self)
01367 {
01368 get_dat1(self);
01369 return f_fdiv(dat->num, dat->den);
01370 }
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383 static VALUE
01384 nurat_to_r(VALUE self)
01385 {
01386 return self;
01387 }
01388
01389 #define id_ceil rb_intern("ceil")
01390 #define f_ceil(x) rb_funcall((x), id_ceil, 0)
01391
01392 #define id_quo rb_intern("quo")
01393 #define f_quo(x,y) rb_funcall((x), id_quo, 1, (y))
01394
01395 #define f_reciprocal(x) f_quo(ONE, (x))
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
01453
01454
01455
01456 static void
01457 nurat_rationalize_internal(VALUE a, VALUE b, VALUE *p, VALUE *q)
01458 {
01459 VALUE c, k, t, p0, p1, p2, q0, q1, q2;
01460
01461 p0 = ZERO;
01462 p1 = ONE;
01463 q0 = ONE;
01464 q1 = ZERO;
01465
01466 while (1) {
01467 c = f_ceil(a);
01468 if (f_lt_p(c, b))
01469 break;
01470 k = f_sub(c, ONE);
01471 p2 = f_add(f_mul(k, p1), p0);
01472 q2 = f_add(f_mul(k, q1), q0);
01473 t = f_reciprocal(f_sub(b, k));
01474 b = f_reciprocal(f_sub(a, k));
01475 a = t;
01476 p0 = p1;
01477 q0 = q1;
01478 p1 = p2;
01479 q1 = q2;
01480 }
01481 *p = f_add(f_mul(c, p1), p0);
01482 *q = f_add(f_mul(c, q1), q0);
01483 }
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501 static VALUE
01502 nurat_rationalize(int argc, VALUE *argv, VALUE self)
01503 {
01504 VALUE e, a, b, p, q;
01505
01506 if (argc == 0)
01507 return self;
01508
01509 if (f_negative_p(self))
01510 return f_negate(nurat_rationalize(argc, argv, f_abs(self)));
01511
01512 rb_scan_args(argc, argv, "01", &e);
01513 e = f_abs(e);
01514 a = f_sub(self, e);
01515 b = f_add(self, e);
01516
01517 if (f_eqeq_p(a, b))
01518 return self;
01519
01520 nurat_rationalize_internal(a, b, &p, &q);
01521 return f_rational_new2(CLASS_OF(self), p, q);
01522 }
01523
01524
01525 static VALUE
01526 nurat_hash(VALUE self)
01527 {
01528 st_index_t v, h[2];
01529 VALUE n;
01530
01531 get_dat1(self);
01532 n = rb_hash(dat->num);
01533 h[0] = NUM2LONG(n);
01534 n = rb_hash(dat->den);
01535 h[1] = NUM2LONG(n);
01536 v = rb_memhash(h, sizeof(h));
01537 return LONG2FIX(v);
01538 }
01539
01540 static VALUE
01541 f_format(VALUE self, VALUE (*func)(VALUE))
01542 {
01543 VALUE s;
01544 get_dat1(self);
01545
01546 s = (*func)(dat->num);
01547 rb_str_cat2(s, "/");
01548 rb_str_concat(s, (*func)(dat->den));
01549
01550 return s;
01551 }
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565 static VALUE
01566 nurat_to_s(VALUE self)
01567 {
01568 return f_format(self, f_to_s);
01569 }
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583 static VALUE
01584 nurat_inspect(VALUE self)
01585 {
01586 VALUE s;
01587
01588 s = rb_usascii_str_new2("(");
01589 rb_str_concat(s, f_format(self, f_inspect));
01590 rb_str_cat2(s, ")");
01591
01592 return s;
01593 }
01594
01595
01596 static VALUE
01597 nurat_marshal_dump(VALUE self)
01598 {
01599 VALUE a;
01600 get_dat1(self);
01601
01602 a = rb_assoc_new(dat->num, dat->den);
01603 rb_copy_generic_ivar(a, self);
01604 return a;
01605 }
01606
01607
01608 static VALUE
01609 nurat_marshal_load(VALUE self, VALUE a)
01610 {
01611 get_dat1(self);
01612 Check_Type(a, T_ARRAY);
01613 if (RARRAY_LEN(a) != 2)
01614 rb_raise(rb_eArgError, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a));
01615 dat->num = RARRAY_PTR(a)[0];
01616 dat->den = RARRAY_PTR(a)[1];
01617 rb_copy_generic_ivar(self, a);
01618
01619 if (f_zero_p(dat->den))
01620 rb_raise_zerodiv();
01621
01622 return self;
01623 }
01624
01625
01626
01627 VALUE
01628 rb_rational_reciprocal(VALUE x)
01629 {
01630 get_dat1(x);
01631 return f_rational_new_no_reduce2(CLASS_OF(x), dat->den, dat->num);
01632 }
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647 VALUE
01648 rb_gcd(VALUE self, VALUE other)
01649 {
01650 other = nurat_int_value(other);
01651 return f_gcd(self, other);
01652 }
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667 VALUE
01668 rb_lcm(VALUE self, VALUE other)
01669 {
01670 other = nurat_int_value(other);
01671 return f_lcm(self, other);
01672 }
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686 VALUE
01687 rb_gcdlcm(VALUE self, VALUE other)
01688 {
01689 other = nurat_int_value(other);
01690 return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
01691 }
01692
01693 VALUE
01694 rb_rational_raw(VALUE x, VALUE y)
01695 {
01696 return nurat_s_new_internal(rb_cRational, x, y);
01697 }
01698
01699 VALUE
01700 rb_rational_new(VALUE x, VALUE y)
01701 {
01702 return nurat_s_canonicalize_internal(rb_cRational, x, y);
01703 }
01704
01705 static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
01706
01707 VALUE
01708 rb_Rational(VALUE x, VALUE y)
01709 {
01710 VALUE a[2];
01711 a[0] = x;
01712 a[1] = y;
01713 return nurat_s_convert(2, a, rb_cRational);
01714 }
01715
01716 #define id_numerator rb_intern("numerator")
01717 #define f_numerator(x) rb_funcall((x), id_numerator, 0)
01718
01719 #define id_denominator rb_intern("denominator")
01720 #define f_denominator(x) rb_funcall((x), id_denominator, 0)
01721
01722 #define id_to_r rb_intern("to_r")
01723 #define f_to_r(x) rb_funcall((x), id_to_r, 0)
01724
01725
01726
01727
01728
01729
01730
01731 static VALUE
01732 numeric_numerator(VALUE self)
01733 {
01734 return f_numerator(f_to_r(self));
01735 }
01736
01737
01738
01739
01740
01741
01742
01743 static VALUE
01744 numeric_denominator(VALUE self)
01745 {
01746 return f_denominator(f_to_r(self));
01747 }
01748
01749
01750
01751
01752
01753
01754
01755 static VALUE
01756 integer_numerator(VALUE self)
01757 {
01758 return self;
01759 }
01760
01761
01762
01763
01764
01765
01766
01767 static VALUE
01768 integer_denominator(VALUE self)
01769 {
01770 return INT2FIX(1);
01771 }
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785 static VALUE
01786 float_numerator(VALUE self)
01787 {
01788 double d = RFLOAT_VALUE(self);
01789 if (isinf(d) || isnan(d))
01790 return self;
01791 return rb_call_super(0, 0);
01792 }
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803 static VALUE
01804 float_denominator(VALUE self)
01805 {
01806 double d = RFLOAT_VALUE(self);
01807 if (isinf(d) || isnan(d))
01808 return INT2FIX(1);
01809 return rb_call_super(0, 0);
01810 }
01811
01812
01813
01814
01815
01816
01817
01818 static VALUE
01819 nilclass_to_r(VALUE self)
01820 {
01821 return rb_rational_new1(INT2FIX(0));
01822 }
01823
01824
01825
01826
01827
01828
01829
01830
01831 static VALUE
01832 nilclass_rationalize(int argc, VALUE *argv, VALUE self)
01833 {
01834 rb_scan_args(argc, argv, "01", NULL);
01835 return nilclass_to_r(self);
01836 }
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849 static VALUE
01850 integer_to_r(VALUE self)
01851 {
01852 return rb_rational_new1(self);
01853 }
01854
01855
01856
01857
01858
01859
01860
01861
01862 static VALUE
01863 integer_rationalize(int argc, VALUE *argv, VALUE self)
01864 {
01865 rb_scan_args(argc, argv, "01", NULL);
01866 return integer_to_r(self);
01867 }
01868
01869 static void
01870 float_decode_internal(VALUE self, VALUE *rf, VALUE *rn)
01871 {
01872 double f;
01873 int n;
01874
01875 f = frexp(RFLOAT_VALUE(self), &n);
01876 f = ldexp(f, DBL_MANT_DIG);
01877 n -= DBL_MANT_DIG;
01878 *rf = rb_dbl2big(f);
01879 *rn = INT2FIX(n);
01880 }
01881
01882 #if 0
01883 static VALUE
01884 float_decode(VALUE self)
01885 {
01886 VALUE f, n;
01887
01888 float_decode_internal(self, &f, &n);
01889 return rb_assoc_new(f, n);
01890 }
01891 #endif
01892
01893 #define id_lshift rb_intern("<<")
01894 #define f_lshift(x,n) rb_funcall((x), id_lshift, 1, (n))
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912 static VALUE
01913 float_to_r(VALUE self)
01914 {
01915 VALUE f, n;
01916
01917 float_decode_internal(self, &f, &n);
01918 #if FLT_RADIX == 2
01919 {
01920 long ln = FIX2LONG(n);
01921
01922 if (ln == 0)
01923 return f_to_r(f);
01924 if (ln > 0)
01925 return f_to_r(f_lshift(f, n));
01926 ln = -ln;
01927 return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln)));
01928 }
01929 #else
01930 return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n)));
01931 #endif
01932 }
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948 static VALUE
01949 float_rationalize(int argc, VALUE *argv, VALUE self)
01950 {
01951 VALUE e, a, b, p, q;
01952
01953 if (f_negative_p(self))
01954 return f_negate(float_rationalize(argc, argv, f_abs(self)));
01955
01956 rb_scan_args(argc, argv, "01", &e);
01957
01958 if (argc != 0) {
01959 e = f_abs(e);
01960 a = f_sub(self, e);
01961 b = f_add(self, e);
01962 }
01963 else {
01964 VALUE f, n;
01965
01966 float_decode_internal(self, &f, &n);
01967 if (f_zero_p(f) || f_positive_p(n))
01968 return rb_rational_new1(f_lshift(f, n));
01969
01970 #if FLT_RADIX == 2
01971 a = rb_rational_new2(f_sub(f_mul(TWO, f), ONE),
01972 f_lshift(ONE, f_sub(ONE, n)));
01973 b = rb_rational_new2(f_add(f_mul(TWO, f), ONE),
01974 f_lshift(ONE, f_sub(ONE, n)));
01975 #else
01976 a = rb_rational_new2(f_sub(f_mul(INT2FIX(FLT_RADIX), f),
01977 INT2FIX(FLT_RADIX - 1)),
01978 f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n)));
01979 b = rb_rational_new2(f_add(f_mul(INT2FIX(FLT_RADIX), f),
01980 INT2FIX(FLT_RADIX - 1)),
01981 f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n)));
01982 #endif
01983 }
01984
01985 if (f_eqeq_p(a, b))
01986 return f_to_r(self);
01987
01988 nurat_rationalize_internal(a, b, &p, &q);
01989 return rb_rational_new2(p, q);
01990 }
01991
01992 static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
01993
01994 #define WS "\\s*"
01995 #define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
01996 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
01997 #define DENOMINATOR DIGITS
01998 #define PATTERN "\\A" WS "([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?" WS
01999
02000 static void
02001 make_patterns(void)
02002 {
02003 static const char rat_pat_source[] = PATTERN;
02004 static const char an_e_pat_source[] = "[eE]";
02005 static const char a_dot_pat_source[] = "\\.";
02006 static const char underscores_pat_source[] = "_+";
02007
02008 if (rat_pat) return;
02009
02010 rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
02011 rb_gc_register_mark_object(rat_pat);
02012
02013 an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
02014 rb_gc_register_mark_object(an_e_pat);
02015
02016 a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
02017 rb_gc_register_mark_object(a_dot_pat);
02018
02019 underscores_pat = rb_reg_new(underscores_pat_source,
02020 sizeof underscores_pat_source - 1, 0);
02021 rb_gc_register_mark_object(underscores_pat);
02022
02023 an_underscore = rb_usascii_str_new2("_");
02024 rb_gc_register_mark_object(an_underscore);
02025 }
02026
02027 #define id_match rb_intern("match")
02028 #define f_match(x,y) rb_funcall((x), id_match, 1, (y))
02029
02030 #define id_split rb_intern("split")
02031 #define f_split(x,y) rb_funcall((x), id_split, 1, (y))
02032
02033 #include <ctype.h>
02034
02035 static VALUE
02036 string_to_r_internal(VALUE self)
02037 {
02038 VALUE s, m;
02039
02040 s = self;
02041
02042 if (RSTRING_LEN(s) == 0)
02043 return rb_assoc_new(Qnil, self);
02044
02045 m = f_match(rat_pat, s);
02046
02047 if (!NIL_P(m)) {
02048 VALUE v, ifp, exp, ip, fp;
02049 VALUE si = rb_reg_nth_match(1, m);
02050 VALUE nu = rb_reg_nth_match(2, m);
02051 VALUE de = rb_reg_nth_match(3, m);
02052 VALUE re = rb_reg_match_post(m);
02053
02054 {
02055 VALUE a;
02056
02057 if (!strpbrk(RSTRING_PTR(nu), "eE")) {
02058 ifp = nu;
02059 exp = Qnil;
02060 }
02061 else {
02062 a = f_split(nu, an_e_pat);
02063 ifp = RARRAY_PTR(a)[0];
02064 if (RARRAY_LEN(a) != 2)
02065 exp = Qnil;
02066 else
02067 exp = RARRAY_PTR(a)[1];
02068 }
02069
02070 if (!strchr(RSTRING_PTR(ifp), '.')) {
02071 ip = ifp;
02072 fp = Qnil;
02073 }
02074 else {
02075 a = f_split(ifp, a_dot_pat);
02076 ip = RARRAY_PTR(a)[0];
02077 if (RARRAY_LEN(a) != 2)
02078 fp = Qnil;
02079 else
02080 fp = RARRAY_PTR(a)[1];
02081 }
02082 }
02083
02084 v = rb_rational_new1(f_to_i(ip));
02085
02086 if (!NIL_P(fp)) {
02087 char *p = RSTRING_PTR(fp);
02088 long count = 0;
02089 VALUE l;
02090
02091 while (*p) {
02092 if (rb_isdigit(*p))
02093 count++;
02094 p++;
02095 }
02096 l = f_expt10(LONG2NUM(count));
02097 v = f_mul(v, l);
02098 v = f_add(v, f_to_i(fp));
02099 v = f_div(v, l);
02100 }
02101 if (!NIL_P(si) && *RSTRING_PTR(si) == '-')
02102 v = f_negate(v);
02103 if (!NIL_P(exp))
02104 v = f_mul(v, f_expt10(f_to_i(exp)));
02105 #if 0
02106 if (!NIL_P(de) && (!NIL_P(fp) || !NIL_P(exp)))
02107 return rb_assoc_new(v, rb_usascii_str_new2("dummy"));
02108 #endif
02109 if (!NIL_P(de))
02110 v = f_div(v, f_to_i(de));
02111
02112 return rb_assoc_new(v, re);
02113 }
02114 return rb_assoc_new(Qnil, self);
02115 }
02116
02117 static VALUE
02118 string_to_r_strict(VALUE self)
02119 {
02120 VALUE a = string_to_r_internal(self);
02121 if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
02122 VALUE s = f_inspect(self);
02123 rb_raise(rb_eArgError, "invalid value for convert(): %s",
02124 StringValuePtr(s));
02125 }
02126 return RARRAY_PTR(a)[0];
02127 }
02128
02129 #define id_gsub rb_intern("gsub")
02130 #define f_gsub(x,y,z) rb_funcall((x), id_gsub, 2, (y), (z))
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155 static VALUE
02156 string_to_r(VALUE self)
02157 {
02158 VALUE s, a, a1, backref;
02159
02160 backref = rb_backref_get();
02161 rb_match_busy(backref);
02162
02163 s = f_gsub(self, underscores_pat, an_underscore);
02164 a = string_to_r_internal(s);
02165
02166 rb_backref_set(backref);
02167
02168 a1 = RARRAY_PTR(a)[0];
02169 if (!NIL_P(a1)) {
02170 if (TYPE(a1) == T_FLOAT)
02171 rb_raise(rb_eFloatDomainError, "Infinity");
02172 return a1;
02173 }
02174 return rb_rational_new1(INT2FIX(0));
02175 }
02176
02177 #define id_to_r rb_intern("to_r")
02178 #define f_to_r(x) rb_funcall((x), id_to_r, 0)
02179
02180 static VALUE
02181 nurat_s_convert(int argc, VALUE *argv, VALUE klass)
02182 {
02183 VALUE a1, a2, backref;
02184
02185 rb_scan_args(argc, argv, "11", &a1, &a2);
02186
02187 if (NIL_P(a1) || (argc == 2 && NIL_P(a2)))
02188 rb_raise(rb_eTypeError, "can't convert nil into Rational");
02189
02190 switch (TYPE(a1)) {
02191 case T_COMPLEX:
02192 if (k_exact_zero_p(RCOMPLEX(a1)->imag))
02193 a1 = RCOMPLEX(a1)->real;
02194 }
02195
02196 switch (TYPE(a2)) {
02197 case T_COMPLEX:
02198 if (k_exact_zero_p(RCOMPLEX(a2)->imag))
02199 a2 = RCOMPLEX(a2)->real;
02200 }
02201
02202 backref = rb_backref_get();
02203 rb_match_busy(backref);
02204
02205 switch (TYPE(a1)) {
02206 case T_FIXNUM:
02207 case T_BIGNUM:
02208 break;
02209 case T_FLOAT:
02210 a1 = f_to_r(a1);
02211 break;
02212 case T_STRING:
02213 a1 = string_to_r_strict(a1);
02214 break;
02215 }
02216
02217 switch (TYPE(a2)) {
02218 case T_FIXNUM:
02219 case T_BIGNUM:
02220 break;
02221 case T_FLOAT:
02222 a2 = f_to_r(a2);
02223 break;
02224 case T_STRING:
02225 a2 = string_to_r_strict(a2);
02226 break;
02227 }
02228
02229 rb_backref_set(backref);
02230
02231 switch (TYPE(a1)) {
02232 case T_RATIONAL:
02233 if (argc == 1 || (k_exact_one_p(a2)))
02234 return a1;
02235 }
02236
02237 if (argc == 1) {
02238 if (!(k_numeric_p(a1) && k_integer_p(a1)))
02239 return rb_convert_type(a1, T_RATIONAL, "Rational", "to_r");
02240 }
02241 else {
02242 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
02243 (!f_integer_p(a1) || !f_integer_p(a2)))
02244 return f_div(a1, a2);
02245 }
02246
02247 {
02248 VALUE argv2[2];
02249 argv2[0] = a1;
02250 argv2[1] = a2;
02251 return nurat_s_new(argc, argv2, klass);
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
02292
02293
02294
02295 void
02296 Init_Rational(void)
02297 {
02298 #undef rb_intern
02299 #define rb_intern(str) rb_intern_const(str)
02300
02301 assert(fprintf(stderr, "assert() is now active\n"));
02302
02303 id_abs = rb_intern("abs");
02304 id_cmp = rb_intern("<=>");
02305 id_convert = rb_intern("convert");
02306 id_eqeq_p = rb_intern("==");
02307 id_expt = rb_intern("**");
02308 id_fdiv = rb_intern("fdiv");
02309 id_floor = rb_intern("floor");
02310 id_idiv = rb_intern("div");
02311 id_inspect = rb_intern("inspect");
02312 id_integer_p = rb_intern("integer?");
02313 id_negate = rb_intern("-@");
02314 id_to_f = rb_intern("to_f");
02315 id_to_i = rb_intern("to_i");
02316 id_to_s = rb_intern("to_s");
02317 id_truncate = rb_intern("truncate");
02318
02319 rb_cRational = rb_define_class("Rational", rb_cNumeric);
02320
02321 rb_define_alloc_func(rb_cRational, nurat_s_alloc);
02322 rb_undef_method(CLASS_OF(rb_cRational), "allocate");
02323
02324 #if 0
02325 rb_define_private_method(CLASS_OF(rb_cRational), "new!", nurat_s_new_bang, -1);
02326 rb_define_private_method(CLASS_OF(rb_cRational), "new", nurat_s_new, -1);
02327 #else
02328 rb_undef_method(CLASS_OF(rb_cRational), "new");
02329 #endif
02330
02331 rb_define_global_function("Rational", nurat_f_rational, -1);
02332
02333 rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
02334 rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
02335
02336 rb_define_method(rb_cRational, "+", nurat_add, 1);
02337 rb_define_method(rb_cRational, "-", nurat_sub, 1);
02338 rb_define_method(rb_cRational, "*", nurat_mul, 1);
02339 rb_define_method(rb_cRational, "/", nurat_div, 1);
02340 rb_define_method(rb_cRational, "quo", nurat_div, 1);
02341 rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
02342 rb_define_method(rb_cRational, "**", nurat_expt, 1);
02343
02344 rb_define_method(rb_cRational, "<=>", nurat_cmp, 1);
02345 rb_define_method(rb_cRational, "==", nurat_eqeq_p, 1);
02346 rb_define_method(rb_cRational, "coerce", nurat_coerce, 1);
02347
02348 #if 0
02349 rb_define_method(rb_cRational, "//", nurat_idiv, 1);
02350 #endif
02351
02352 #if 0
02353 rb_define_method(rb_cRational, "quot", nurat_quot, 1);
02354 rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1);
02355 #endif
02356
02357 #if 0
02358 rb_define_method(rb_cRational, "rational?", nurat_true, 0);
02359 rb_define_method(rb_cRational, "exact?", nurat_true, 0);
02360 #endif
02361
02362 rb_define_method(rb_cRational, "floor", nurat_floor_n, -1);
02363 rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1);
02364 rb_define_method(rb_cRational, "truncate", nurat_truncate_n, -1);
02365 rb_define_method(rb_cRational, "round", nurat_round_n, -1);
02366
02367 rb_define_method(rb_cRational, "to_i", nurat_truncate, 0);
02368 rb_define_method(rb_cRational, "to_f", nurat_to_f, 0);
02369 rb_define_method(rb_cRational, "to_r", nurat_to_r, 0);
02370 rb_define_method(rb_cRational, "rationalize", nurat_rationalize, -1);
02371
02372 rb_define_method(rb_cRational, "hash", nurat_hash, 0);
02373
02374 rb_define_method(rb_cRational, "to_s", nurat_to_s, 0);
02375 rb_define_method(rb_cRational, "inspect", nurat_inspect, 0);
02376
02377 rb_define_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
02378 rb_define_method(rb_cRational, "marshal_load", nurat_marshal_load, 1);
02379
02380
02381
02382 rb_define_method(rb_cInteger, "gcd", rb_gcd, 1);
02383 rb_define_method(rb_cInteger, "lcm", rb_lcm, 1);
02384 rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1);
02385
02386 rb_define_method(rb_cNumeric, "numerator", numeric_numerator, 0);
02387 rb_define_method(rb_cNumeric, "denominator", numeric_denominator, 0);
02388
02389 rb_define_method(rb_cInteger, "numerator", integer_numerator, 0);
02390 rb_define_method(rb_cInteger, "denominator", integer_denominator, 0);
02391
02392 rb_define_method(rb_cFloat, "numerator", float_numerator, 0);
02393 rb_define_method(rb_cFloat, "denominator", float_denominator, 0);
02394
02395 rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
02396 rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1);
02397 rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
02398 rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1);
02399 rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
02400 rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1);
02401
02402 make_patterns();
02403
02404 rb_define_method(rb_cString, "to_r", string_to_r, 0);
02405
02406 rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1);
02407 }
02408
02409
02410
02411
02412
02413
02414