|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /* 00002 rational.c: Coded by Tadayoshi Funaba 2008,2009 00003 00004 This implementation is based on Keiju Ishitsuka's Rational library 00005 which is written in ruby. 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 /* NOTREACHED */ 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 * call-seq: 00532 * Rational(x[, y]) -> numeric 00533 * 00534 * Returns x/y; 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 * call-seq: 00544 * rat.numerator -> integer 00545 * 00546 * Returns the numerator. 00547 * 00548 * For example: 00549 * 00550 * Rational(7).numerator #=> 7 00551 * Rational(7, 1).numerator #=> 7 00552 * Rational(9, -4).numerator #=> -9 00553 * Rational(-2, -10).numerator #=> 1 00554 */ 00555 static VALUE 00556 nurat_numerator(VALUE self) 00557 { 00558 get_dat1(self); 00559 return dat->num; 00560 } 00561 00562 /* 00563 * call-seq: 00564 * rat.denominator -> integer 00565 * 00566 * Returns the denominator (always positive). 00567 * 00568 * For example: 00569 * 00570 * Rational(7).denominator #=> 1 00571 * Rational(7, 1).denominator #=> 1 00572 * Rational(9, -4).denominator #=> 4 00573 * Rational(-2, -10).denominator #=> 5 00574 * rat.numerator.gcd(rat.denominator) #=> 1 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 volatile 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 * call-seq: 00670 * rat + numeric -> numeric_result 00671 * 00672 * Performs addition. 00673 * 00674 * For example: 00675 * 00676 * Rational(2, 3) + Rational(2, 3) #=> (4/3) 00677 * Rational(900) + Rational(1) #=> (900/1) 00678 * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18) 00679 * Rational(9, 8) + 4 #=> (41/8) 00680 * Rational(20, 9) + 9.8 #=> 12.022222222222222 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 * call-seq: 00712 * rat - numeric -> numeric_result 00713 * 00714 * Performs subtraction. 00715 * 00716 * For example: 00717 * 00718 * Rational(2, 3) - Rational(2, 3) #=> (0/1) 00719 * Rational(900) - Rational(1) #=> (899/1) 00720 * Rational(-2, 9) - Rational(-9, 2) #=> (77/18) 00721 * Rational(9, 8) - 4 #=> (23/8) 00722 * Rational(20, 9) - 9.8 #=> -7.577777777777778 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 * call-seq: 00793 * rat * numeric -> numeric_result 00794 * 00795 * Performs multiplication. 00796 * 00797 * For example: 00798 * 00799 * Rational(2, 3) * Rational(2, 3) #=> (4/9) 00800 * Rational(900) * Rational(1) #=> (900/1) 00801 * Rational(-2, 9) * Rational(-9, 2) #=> (1/1) 00802 * Rational(9, 8) * 4 #=> (9/2) 00803 * Rational(20, 9) * 9.8 #=> 21.77777777777778 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 * call-seq: 00835 * rat / numeric -> numeric_result 00836 * rat.quo(numeric) -> numeric_result 00837 * 00838 * Performs division. 00839 * 00840 * For example: 00841 * 00842 * Rational(2, 3) / Rational(2, 3) #=> (1/1) 00843 * Rational(900) / Rational(1) #=> (900/1) 00844 * Rational(-2, 9) / Rational(-9, 2) #=> (4/81) 00845 * Rational(9, 8) / 4 #=> (9/32) 00846 * Rational(20, 9) / 9.8 #=> 0.22675736961451246 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 * call-seq: 00886 * rat.fdiv(numeric) -> float 00887 * 00888 * Performs division and returns the value as a float. 00889 * 00890 * For example: 00891 * 00892 * Rational(2, 3).fdiv(1) #=> 0.6666666666666666 00893 * Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333 00894 * Rational(2).fdiv(3) #=> 0.6666666666666666 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 * call-seq: 00906 * rat ** numeric -> numeric_result 00907 * 00908 * Performs exponentiation. 00909 * 00910 * For example: 00911 * 00912 * Rational(2) ** Rational(3) #=> (8/1) 00913 * Rational(10) ** -2 #=> (1/100) 00914 * Rational(10) ** -2.0 #=> 0.01 00915 * Rational(-4) ** Rational(1,2) #=> (1.2246063538223773e-16+2.0i) 00916 * Rational(1, 2) ** 0 #=> (1/1) 00917 * Rational(1, 2) ** 0.0 #=> 1.0 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; /* c14n */ 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 /* fall through */ 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 * call-seq: 00968 * rat <=> numeric -> -1, 0, +1 or nil 00969 * 00970 * Performs comparison and returns -1, 0, or +1. 00971 * 00972 * For example: 00973 * 00974 * Rational(2, 3) <=> Rational(2, 3) #=> 0 00975 * Rational(5) <=> 5 #=> 0 00976 * Rational(2,3) <=> Rational(1,3) #=> 1 00977 * Rational(1,3) <=> 1 #=> -1 00978 * Rational(1,3) <=> 0.3 #=> 1 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); /* c14n */ 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 * call-seq: 01019 * rat == object -> true or false 01020 * 01021 * Returns true if rat equals object numerically. 01022 * 01023 * For example: 01024 * 01025 * Rational(2, 3) == Rational(2, 3) #=> true 01026 * Rational(5) == 5 #=> true 01027 * Rational(0) == 0.0 #=> true 01028 * Rational('1/3') == 0.33 #=> false 01029 * Rational('1/2') == '1/2' #=> false 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 /* :nodoc: */ 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 /* :nodoc: */ 01093 static VALUE 01094 nurat_idiv(VALUE self, VALUE other) 01095 { 01096 return f_idiv(self, other); 01097 } 01098 01099 /* :nodoc: */ 01100 static VALUE 01101 nurat_quot(VALUE self, VALUE other) 01102 { 01103 return f_truncate(f_div(self, other)); 01104 } 01105 01106 /* :nodoc: */ 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 /* :nodoc: */ 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 * call-seq: 01141 * rat.to_i -> integer 01142 * 01143 * Returns the truncated value as an integer. 01144 * 01145 * Equivalent to 01146 * rat.truncate. 01147 * 01148 * For example: 01149 * 01150 * Rational(2, 3).to_i #=> 0 01151 * Rational(3).to_i #=> 3 01152 * Rational(300.6).to_i #=> 300 01153 * Rational(98,71).to_i #=> 1 01154 * Rational(-30,2).to_i #=> -15 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 * call-seq: 01217 * rat.floor -> integer 01218 * rat.floor(precision=0) -> rational 01219 * 01220 * Returns the truncated value (toward negative infinity). 01221 * 01222 * For example: 01223 * 01224 * Rational(3).floor #=> 3 01225 * Rational(2, 3).floor #=> 0 01226 * Rational(-3, 2).floor #=> -1 01227 * 01228 * decimal - 1 2 3 . 4 5 6 01229 * ^ ^ ^ ^ ^ ^ 01230 * precision -3 -2 -1 0 +1 +2 01231 * 01232 * '%f' % Rational('-123.456').floor(+1) #=> "-123.500000" 01233 * '%f' % Rational('-123.456').floor(-1) #=> "-130.000000" 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 * call-seq: 01243 * rat.ceil -> integer 01244 * rat.ceil(precision=0) -> rational 01245 * 01246 * Returns the truncated value (toward positive infinity). 01247 * 01248 * For example: 01249 * 01250 * Rational(3).ceil #=> 3 01251 * Rational(2, 3).ceil #=> 1 01252 * Rational(-3, 2).ceil #=> -1 01253 * 01254 * decimal - 1 2 3 . 4 5 6 01255 * ^ ^ ^ ^ ^ ^ 01256 * precision -3 -2 -1 0 +1 +2 01257 * 01258 * '%f' % Rational('-123.456').ceil(+1) #=> "-123.400000" 01259 * '%f' % Rational('-123.456').ceil(-1) #=> "-120.000000" 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 * call-seq: 01269 * rat.truncate -> integer 01270 * rat.truncate(precision=0) -> rational 01271 * 01272 * Returns the truncated value (toward zero). 01273 * 01274 * For example: 01275 * 01276 * Rational(3).truncate #=> 3 01277 * Rational(2, 3).truncate #=> 0 01278 * Rational(-3, 2).truncate #=> -1 01279 * 01280 * decimal - 1 2 3 . 4 5 6 01281 * ^ ^ ^ ^ ^ ^ 01282 * precision -3 -2 -1 0 +1 +2 01283 * 01284 * '%f' % Rational('-123.456').truncate(+1) #=> "-123.400000" 01285 * '%f' % Rational('-123.456').truncate(-1) #=> "-120.000000" 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 * call-seq: 01295 * rat.round -> integer 01296 * rat.round(precision=0) -> rational 01297 * 01298 * Returns the truncated value (toward the nearest integer; 01299 * 0.5 => 1; -0.5 => -1). 01300 * 01301 * For example: 01302 * 01303 * Rational(3).round #=> 3 01304 * Rational(2, 3).round #=> 1 01305 * Rational(-3, 2).round #=> -2 01306 * 01307 * decimal - 1 2 3 . 4 5 6 01308 * ^ ^ ^ ^ ^ ^ 01309 * precision -3 -2 -1 0 +1 +2 01310 * 01311 * '%f' % Rational('-123.456').round(+1) #=> "-123.500000" 01312 * '%f' % Rational('-123.456').round(-1) #=> "-120.000000" 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 * call-seq: 01322 * rat.to_f -> float 01323 * 01324 * Return the value as a float. 01325 * 01326 * For example: 01327 * 01328 * Rational(2).to_f #=> 2.0 01329 * Rational(9, 4).to_f #=> 2.25 01330 * Rational(-3, 4).to_f #=> -0.75 01331 * Rational(20, 3).to_f #=> 6.666666666666667 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 * call-seq: 01342 * rat.to_r -> self 01343 * 01344 * Returns self. 01345 * 01346 * For example: 01347 * 01348 * Rational(2).to_r #=> (2/1) 01349 * Rational(-8, 6).to_r #=> (-4/3) 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 The algorithm here is the method described in CLISP. Bruno Haible has 01367 graciously given permission to use this algorithm. He says, "You can use 01368 it, if you present the following explanation of the algorithm." 01369 01370 Algorithm (recursively presented): 01371 If x is a rational number, return x. 01372 If x = 0.0, return 0. 01373 If x < 0.0, return (- (rationalize (- x))). 01374 If x > 0.0: 01375 Call (integer-decode-float x). It returns a m,e,s=1 (mantissa, 01376 exponent, sign). 01377 If m = 0 or e >= 0: return x = m*2^e. 01378 Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e 01379 with smallest possible numerator and denominator. 01380 Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e. 01381 But in this case the result will be x itself anyway, regardless of 01382 the choice of a. Therefore we can simply ignore this case. 01383 Note 2: At first, we need to consider the closed interval [a,b]. 01384 but since a and b have the denominator 2^(|e|+1) whereas x itself 01385 has a denominator <= 2^|e|, we can restrict the search to the open 01386 interval (a,b). 01387 So, for given a and b (0 < a < b) we are searching a rational number 01388 y with a <= y <= b. 01389 Recursive algorithm fraction_between(a,b): 01390 c := (ceiling a) 01391 if c < b 01392 then return c ; because a <= c < b, c integer 01393 else 01394 ; a is not integer (otherwise we would have had c = a < b) 01395 k := c-1 ; k = floor(a), k < a < b <= k+1 01396 return y = k + 1/fraction_between(1/(b-k), 1/(a-k)) 01397 ; note 1 <= 1/(b-k) < 1/(a-k) 01398 01399 You can see that we are actually computing a continued fraction expansion. 01400 01401 Algorithm (iterative): 01402 If x is rational, return x. 01403 Call (integer-decode-float x). It returns a m,e,s (mantissa, 01404 exponent, sign). 01405 If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.) 01406 Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1) 01407 (positive and already in lowest terms because the denominator is a 01408 power of two and the numerator is odd). 01409 Start a continued fraction expansion 01410 p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0. 01411 Loop 01412 c := (ceiling a) 01413 if c >= b 01414 then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)), 01415 goto Loop 01416 finally partial_quotient(c). 01417 Here partial_quotient(c) denotes the iteration 01418 i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2]. 01419 At the end, return s * (p[i]/q[i]). 01420 This rational number is already in lowest terms because 01421 p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i. 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 * call-seq: 01455 * rat.rationalize -> self 01456 * rat.rationalize(eps) -> rational 01457 * 01458 * Returns a simpler approximation of the value if an optional 01459 * argument eps is given (rat-|eps| <= result <= rat+|eps|), self 01460 * otherwise. 01461 * 01462 * For example: 01463 * 01464 * r = Rational(5033165, 16777216) 01465 * r.rationalize #=> (5033165/16777216) 01466 * r.rationalize(Rational('0.01')) #=> (3/10) 01467 * r.rationalize(Rational('0.1')) #=> (1/3) 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 /* :nodoc: */ 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 * call-seq: 01523 * rat.to_s -> string 01524 * 01525 * Returns the value as a string. 01526 * 01527 * For example: 01528 * 01529 * Rational(2).to_s #=> "2/1" 01530 * Rational(-8, 6).to_s #=> "-4/3" 01531 * Rational('0.5').to_s #=> "1/2" 01532 */ 01533 static VALUE 01534 nurat_to_s(VALUE self) 01535 { 01536 return f_format(self, f_to_s); 01537 } 01538 01539 /* 01540 * call-seq: 01541 * rat.inspect -> string 01542 * 01543 * Returns the value as a string for inspection. 01544 * 01545 * For example: 01546 * 01547 * Rational(2).inspect #=> "(2/1)" 01548 * Rational(-8, 6).inspect #=> "(-4/3)" 01549 * Rational('0.5').inspect #=> "(1/2)" 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 /* :nodoc: */ 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 /* :nodoc: */ 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 * call-seq: 01602 * int.gcd(int2) -> integer 01603 * 01604 * Returns the greatest common divisor (always positive). 0.gcd(x) 01605 * and x.gcd(0) return abs(x). 01606 * 01607 * For example: 01608 * 01609 * 2.gcd(2) #=> 2 01610 * 3.gcd(-7) #=> 1 01611 * ((1<<31)-1).gcd((1<<61)-1) #=> 1 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 * call-seq: 01622 * int.lcm(int2) -> integer 01623 * 01624 * Returns the least common multiple (always positive). 0.lcm(x) and 01625 * x.lcm(0) return zero. 01626 * 01627 * For example: 01628 * 01629 * 2.lcm(2) #=> 2 01630 * 3.lcm(-7) #=> 21 01631 * ((1<<31)-1).lcm((1<<61)-1) #=> 4951760154835678088235319297 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 * call-seq: 01642 * int.gcdlcm(int2) -> array 01643 * 01644 * Returns an array; [int.gcd(int2), int.lcm(int2)]. 01645 * 01646 * For example: 01647 * 01648 * 2.gcdlcm(2) #=> [2, 2] 01649 * 3.gcdlcm(-7) #=> [1, 21] 01650 * ((1<<31)-1).gcdlcm((1<<61)-1) #=> [1, 4951760154835678088235319297] 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 * call-seq: 01693 * num.numerator -> integer 01694 * 01695 * Returns the numerator. 01696 */ 01697 static VALUE 01698 numeric_numerator(VALUE self) 01699 { 01700 return f_numerator(f_to_r(self)); 01701 } 01702 01703 /* 01704 * call-seq: 01705 * num.denominator -> integer 01706 * 01707 * Returns the denominator (always positive). 01708 */ 01709 static VALUE 01710 numeric_denominator(VALUE self) 01711 { 01712 return f_denominator(f_to_r(self)); 01713 } 01714 01715 /* 01716 * call-seq: 01717 * int.numerator -> self 01718 * 01719 * Returns self. 01720 */ 01721 static VALUE 01722 integer_numerator(VALUE self) 01723 { 01724 return self; 01725 } 01726 01727 /* 01728 * call-seq: 01729 * int.denominator -> 1 01730 * 01731 * Returns 1. 01732 */ 01733 static VALUE 01734 integer_denominator(VALUE self) 01735 { 01736 return INT2FIX(1); 01737 } 01738 01739 /* 01740 * call-seq: 01741 * flo.numerator -> integer 01742 * 01743 * Returns the numerator. The result is machine dependent. 01744 * 01745 * For example: 01746 * 01747 * n = 0.3.numerator #=> 5404319552844595 01748 * d = 0.3.denominator #=> 18014398509481984 01749 * n.fdiv(d) #=> 0.3 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 * call-seq: 01762 * flo.denominator -> integer 01763 * 01764 * Returns the denominator (always positive). The result is machine 01765 * dependent. 01766 * 01767 * See numerator. 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 * call-seq: 01780 * nil.to_r -> (0/1) 01781 * 01782 * Returns zero as a rational. 01783 */ 01784 static VALUE 01785 nilclass_to_r(VALUE self) 01786 { 01787 return rb_rational_new1(INT2FIX(0)); 01788 } 01789 01790 /* 01791 * call-seq: 01792 * nil.rationalize([eps]) -> (0/1) 01793 * 01794 * Returns zero as a rational. An optional argument eps is always 01795 * ignored. 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 * call-seq: 01806 * int.to_r -> rational 01807 * 01808 * Returns the value as a rational. 01809 * 01810 * For example: 01811 * 01812 * 1.to_r #=> (1/1) 01813 * (1<<64).to_r #=> (18446744073709551616/1) 01814 */ 01815 static VALUE 01816 integer_to_r(VALUE self) 01817 { 01818 return rb_rational_new1(self); 01819 } 01820 01821 /* 01822 * call-seq: 01823 * int.rationalize([eps]) -> rational 01824 * 01825 * Returns the value as a rational. An optional argument eps is 01826 * always ignored. 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 * call-seq: 01864 * flt.to_r -> rational 01865 * 01866 * Returns the value as a rational. 01867 * 01868 * NOTE: 0.3.to_r isn't the same as '0.3'.to_r. The latter is 01869 * equivalent to '3/10'.to_r, but the former isn't so. 01870 * 01871 * For example: 01872 * 01873 * 2.0.to_r #=> (2/1) 01874 * 2.5.to_r #=> (5/2) 01875 * -0.75.to_r #=> (-3/4) 01876 * 0.0.to_r #=> (0/1) 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 * call-seq: 01902 * flt.rationalize([eps]) -> rational 01903 * 01904 * Returns a simpler approximation of the value (flt-|eps| <= result 01905 * <= flt+|eps|). if eps is not given, it will be chosen 01906 * automatically. 01907 * 01908 * For example: 01909 * 01910 * 0.3.rationalize #=> (3/10) 01911 * 1.333.rationalize #=> (1333/1000) 01912 * 1.333.rationalize(0.01) #=> (4/3) 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 * call-seq: 02095 * str.to_r -> rational 02096 * 02097 * Returns a rational which denotes the string form. The parser 02098 * ignores leading whitespaces and trailing garbage. Any digit 02099 * sequences can be separated by an underscore. Returns zero for null 02100 * or garbage string. 02101 * 02102 * NOTE: '0.3'.to_r isn't the same as 0.3.to_r. The former is 02103 * equivalent to '3/10'.to_r, but the latter isn't so. 02104 * 02105 * For example: 02106 * 02107 * ' 2 '.to_r #=> (2/1) 02108 * '300/2'.to_r #=> (150/1) 02109 * '-9.2'.to_r #=> (-46/5) 02110 * '-9.2e2'.to_r #=> (-920/1) 02111 * '1_234_567'.to_r #=> (1234567/1) 02112 * '21 june 09'.to_r #=> (21/1) 02113 * '21/06/09'.to_r #=> (7/2) 02114 * 'bwv 1079'.to_r #=> (0/1) 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 * A rational number can be represented as a paired integer number; 02214 * a/b (b>0). Where a is numerator and b is denominator. Integer a 02215 * equals rational a/1 mathematically. 02216 * 02217 * In ruby, you can create rational object with Rational or to_r 02218 * method. The return values will be irreducible. 02219 * 02220 * Rational(1) #=> (1/1) 02221 * Rational(2, 3) #=> (2/3) 02222 * Rational(4, -6) #=> (-2/3) 02223 * 3.to_r #=> (3/1) 02224 * 02225 * You can also create rational object from floating-point numbers or 02226 * strings. 02227 * 02228 * Rational(0.3) #=> (5404319552844595/18014398509481984) 02229 * Rational('0.3') #=> (3/10) 02230 * Rational('2/3') #=> (2/3) 02231 * 02232 * 0.3.to_r #=> (5404319552844595/18014398509481984) 02233 * '0.3'.to_r #=> (3/10) 02234 * '2/3'.to_r #=> (2/3) 02235 * 02236 * A rational object is an exact number, which helps you to write 02237 * program without any rounding errors. 02238 * 02239 * 10.times.inject(0){|t,| t + 0.1} #=> 0.9999999999999999 02240 * 10.times.inject(0){|t,| t + Rational('0.1')} #=> (1/1) 02241 * 02242 * However, when an expression has inexact factor (numerical value or 02243 * operation), will produce an inexact result. 02244 * 02245 * Rational(10) / 3 #=> (10/3) 02246 * Rational(10) / 3.0 #=> 3.3333333333333335 02247 * 02248 * Rational(-8) ** Rational(1, 3) 02249 * #=> (1.0000000000000002+1.7320508075688772i) 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 /* NUBY */ 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 Local variables: 02367 c-file-style: "ruby" 02368 End: 02369 */ 02370
1.7.3