Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /* 00002 rational.c: Coded by Tadayoshi Funaba 2008-2011 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 "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 /* NOTREACHED */ 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 * call-seq: 00549 * Rational(x[, y]) -> numeric 00550 * 00551 * Returns x/y; 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 * call-seq: 00561 * rat.numerator -> integer 00562 * 00563 * Returns the numerator. 00564 * 00565 * For example: 00566 * 00567 * Rational(7).numerator #=> 7 00568 * Rational(7, 1).numerator #=> 7 00569 * Rational(9, -4).numerator #=> -9 00570 * Rational(-2, -10).numerator #=> 1 00571 */ 00572 static VALUE 00573 nurat_numerator(VALUE self) 00574 { 00575 get_dat1(self); 00576 return dat->num; 00577 } 00578 00579 /* 00580 * call-seq: 00581 * rat.denominator -> integer 00582 * 00583 * Returns the denominator (always positive). 00584 * 00585 * For example: 00586 * 00587 * Rational(7).denominator #=> 1 00588 * Rational(7, 1).denominator #=> 1 00589 * Rational(9, -4).denominator #=> 4 00590 * Rational(-2, -10).denominator #=> 5 00591 * rat.numerator.gcd(rat.denominator) #=> 1 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 * call-seq: 00687 * rat + numeric -> numeric 00688 * 00689 * Performs addition. 00690 * 00691 * For example: 00692 * 00693 * Rational(2, 3) + Rational(2, 3) #=> (4/3) 00694 * Rational(900) + Rational(1) #=> (900/1) 00695 * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18) 00696 * Rational(9, 8) + 4 #=> (41/8) 00697 * Rational(20, 9) + 9.8 #=> 12.022222222222222 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 * call-seq: 00729 * rat - numeric -> numeric 00730 * 00731 * Performs subtraction. 00732 * 00733 * For example: 00734 * 00735 * Rational(2, 3) - Rational(2, 3) #=> (0/1) 00736 * Rational(900) - Rational(1) #=> (899/1) 00737 * Rational(-2, 9) - Rational(-9, 2) #=> (77/18) 00738 * Rational(9, 8) - 4 #=> (23/8) 00739 * Rational(20, 9) - 9.8 #=> -7.577777777777778 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 * call-seq: 00810 * rat * numeric -> numeric 00811 * 00812 * Performs multiplication. 00813 * 00814 * For example: 00815 * 00816 * Rational(2, 3) * Rational(2, 3) #=> (4/9) 00817 * Rational(900) * Rational(1) #=> (900/1) 00818 * Rational(-2, 9) * Rational(-9, 2) #=> (1/1) 00819 * Rational(9, 8) * 4 #=> (9/2) 00820 * Rational(20, 9) * 9.8 #=> 21.77777777777778 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 * call-seq: 00852 * rat / numeric -> numeric 00853 * rat.quo(numeric) -> numeric 00854 * 00855 * Performs division. 00856 * 00857 * For example: 00858 * 00859 * Rational(2, 3) / Rational(2, 3) #=> (1/1) 00860 * Rational(900) / Rational(1) #=> (900/1) 00861 * Rational(-2, 9) / Rational(-9, 2) #=> (4/81) 00862 * Rational(9, 8) / 4 #=> (9/32) 00863 * Rational(20, 9) / 9.8 #=> 0.22675736961451246 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 * call-seq: 00913 * rat.fdiv(numeric) -> float 00914 * 00915 * Performs division and returns the value as a float. 00916 * 00917 * For example: 00918 * 00919 * Rational(2, 3).fdiv(1) #=> 0.6666666666666666 00920 * Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333 00921 * Rational(2).fdiv(3) #=> 0.6666666666666666 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 * call-seq: 00933 * rat ** numeric -> numeric 00934 * 00935 * Performs exponentiation. 00936 * 00937 * For example: 00938 * 00939 * Rational(2) ** Rational(3) #=> (8/1) 00940 * Rational(10) ** -2 #=> (1/100) 00941 * Rational(10) ** -2.0 #=> 0.01 00942 * Rational(-4) ** Rational(1,2) #=> (1.2246063538223773e-16+2.0i) 00943 * Rational(1, 2) ** 0 #=> (1/1) 00944 * Rational(1, 2) ** 0.0 #=> 1.0 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; /* c14n */ 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 /* fall through */ 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 * call-seq: 00995 * rat <=> numeric -> -1, 0, +1 or nil 00996 * 00997 * Performs comparison and returns -1, 0, or +1. 00998 * 00999 * For example: 01000 * 01001 * Rational(2, 3) <=> Rational(2, 3) #=> 0 01002 * Rational(5) <=> 5 #=> 0 01003 * Rational(2,3) <=> Rational(1,3) #=> 1 01004 * Rational(1,3) <=> 1 #=> -1 01005 * Rational(1,3) <=> 0.3 #=> 1 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); /* c14n */ 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 * call-seq: 01046 * rat == object -> true or false 01047 * 01048 * Returns true if rat equals object numerically. 01049 * 01050 * For example: 01051 * 01052 * Rational(2, 3) == Rational(2, 3) #=> true 01053 * Rational(5) == 5 #=> true 01054 * Rational(0) == 0.0 #=> true 01055 * Rational('1/3') == 0.33 #=> false 01056 * Rational('1/2') == '1/2' #=> false 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 /* :nodoc: */ 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 /* :nodoc: */ 01122 static VALUE 01123 nurat_idiv(VALUE self, VALUE other) 01124 { 01125 return f_idiv(self, other); 01126 } 01127 01128 /* :nodoc: */ 01129 static VALUE 01130 nurat_quot(VALUE self, VALUE other) 01131 { 01132 return f_truncate(f_div(self, other)); 01133 } 01134 01135 /* :nodoc: */ 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 /* :nodoc: */ 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 * call-seq: 01169 * rat.to_i -> integer 01170 * 01171 * Returns the truncated value as an integer. 01172 * 01173 * Equivalent to 01174 * rat.truncate. 01175 * 01176 * For example: 01177 * 01178 * Rational(2, 3).to_i #=> 0 01179 * Rational(3).to_i #=> 3 01180 * Rational(300.6).to_i #=> 300 01181 * Rational(98,71).to_i #=> 1 01182 * Rational(-30,2).to_i #=> -15 01183 */ 01184 static VALUE 01185 nurat_truncate(VALUE self) 01186 { 01187 get_dat1(self); 01188 if (f_negative_p(dat->num)) 01189 return f_negate(f_idiv(f_negate(dat->num), dat->den)); 01190 return f_idiv(dat->num, dat->den); 01191 } 01192 01193 static VALUE 01194 nurat_round(VALUE self) 01195 { 01196 VALUE num, den, neg; 01197 01198 get_dat1(self); 01199 01200 num = dat->num; 01201 den = dat->den; 01202 neg = f_negative_p(num); 01203 01204 if (neg) 01205 num = f_negate(num); 01206 01207 num = f_add(f_mul(num, TWO), den); 01208 den = f_mul(den, TWO); 01209 num = f_idiv(num, den); 01210 01211 if (neg) 01212 num = f_negate(num); 01213 01214 return num; 01215 } 01216 01217 static VALUE 01218 f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE)) 01219 { 01220 VALUE n, b, s; 01221 01222 if (argc == 0) 01223 return (*func)(self); 01224 01225 rb_scan_args(argc, argv, "01", &n); 01226 01227 if (!k_integer_p(n)) 01228 rb_raise(rb_eTypeError, "not an integer"); 01229 01230 b = f_expt10(n); 01231 s = f_mul(self, b); 01232 01233 s = (*func)(s); 01234 01235 s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b); 01236 01237 if (f_lt_p(n, ONE)) 01238 s = f_to_i(s); 01239 01240 return s; 01241 } 01242 01243 /* 01244 * call-seq: 01245 * rat.floor -> integer 01246 * rat.floor(precision=0) -> rational 01247 * 01248 * Returns the truncated value (toward negative infinity). 01249 * 01250 * For example: 01251 * 01252 * Rational(3).floor #=> 3 01253 * Rational(2, 3).floor #=> 0 01254 * Rational(-3, 2).floor #=> -1 01255 * 01256 * decimal - 1 2 3 . 4 5 6 01257 * ^ ^ ^ ^ ^ ^ 01258 * precision -3 -2 -1 0 +1 +2 01259 * 01260 * '%f' % Rational('-123.456').floor(+1) #=> "-123.500000" 01261 * '%f' % Rational('-123.456').floor(-1) #=> "-130.000000" 01262 */ 01263 static VALUE 01264 nurat_floor_n(int argc, VALUE *argv, VALUE self) 01265 { 01266 return f_round_common(argc, argv, self, nurat_floor); 01267 } 01268 01269 /* 01270 * call-seq: 01271 * rat.ceil -> integer 01272 * rat.ceil(precision=0) -> rational 01273 * 01274 * Returns the truncated value (toward positive infinity). 01275 * 01276 * For example: 01277 * 01278 * Rational(3).ceil #=> 3 01279 * Rational(2, 3).ceil #=> 1 01280 * Rational(-3, 2).ceil #=> -1 01281 * 01282 * decimal - 1 2 3 . 4 5 6 01283 * ^ ^ ^ ^ ^ ^ 01284 * precision -3 -2 -1 0 +1 +2 01285 * 01286 * '%f' % Rational('-123.456').ceil(+1) #=> "-123.400000" 01287 * '%f' % Rational('-123.456').ceil(-1) #=> "-120.000000" 01288 */ 01289 static VALUE 01290 nurat_ceil_n(int argc, VALUE *argv, VALUE self) 01291 { 01292 return f_round_common(argc, argv, self, nurat_ceil); 01293 } 01294 01295 /* 01296 * call-seq: 01297 * rat.truncate -> integer 01298 * rat.truncate(precision=0) -> rational 01299 * 01300 * Returns the truncated value (toward zero). 01301 * 01302 * For example: 01303 * 01304 * Rational(3).truncate #=> 3 01305 * Rational(2, 3).truncate #=> 0 01306 * Rational(-3, 2).truncate #=> -1 01307 * 01308 * decimal - 1 2 3 . 4 5 6 01309 * ^ ^ ^ ^ ^ ^ 01310 * precision -3 -2 -1 0 +1 +2 01311 * 01312 * '%f' % Rational('-123.456').truncate(+1) #=> "-123.400000" 01313 * '%f' % Rational('-123.456').truncate(-1) #=> "-120.000000" 01314 */ 01315 static VALUE 01316 nurat_truncate_n(int argc, VALUE *argv, VALUE self) 01317 { 01318 return f_round_common(argc, argv, self, nurat_truncate); 01319 } 01320 01321 /* 01322 * call-seq: 01323 * rat.round -> integer 01324 * rat.round(precision=0) -> rational 01325 * 01326 * Returns the truncated value (toward the nearest integer; 01327 * 0.5 => 1; -0.5 => -1). 01328 * 01329 * For example: 01330 * 01331 * Rational(3).round #=> 3 01332 * Rational(2, 3).round #=> 1 01333 * Rational(-3, 2).round #=> -2 01334 * 01335 * decimal - 1 2 3 . 4 5 6 01336 * ^ ^ ^ ^ ^ ^ 01337 * precision -3 -2 -1 0 +1 +2 01338 * 01339 * '%f' % Rational('-123.456').round(+1) #=> "-123.500000" 01340 * '%f' % Rational('-123.456').round(-1) #=> "-120.000000" 01341 */ 01342 static VALUE 01343 nurat_round_n(int argc, VALUE *argv, VALUE self) 01344 { 01345 return f_round_common(argc, argv, self, nurat_round); 01346 } 01347 01348 /* 01349 * call-seq: 01350 * rat.to_f -> float 01351 * 01352 * Return the value as a float. 01353 * 01354 * For example: 01355 * 01356 * Rational(2).to_f #=> 2.0 01357 * Rational(9, 4).to_f #=> 2.25 01358 * Rational(-3, 4).to_f #=> -0.75 01359 * Rational(20, 3).to_f #=> 6.666666666666667 01360 */ 01361 static VALUE 01362 nurat_to_f(VALUE self) 01363 { 01364 get_dat1(self); 01365 return f_fdiv(dat->num, dat->den); 01366 } 01367 01368 /* 01369 * call-seq: 01370 * rat.to_r -> self 01371 * 01372 * Returns self. 01373 * 01374 * For example: 01375 * 01376 * Rational(2).to_r #=> (2/1) 01377 * Rational(-8, 6).to_r #=> (-4/3) 01378 */ 01379 static VALUE 01380 nurat_to_r(VALUE self) 01381 { 01382 return self; 01383 } 01384 01385 #define id_ceil rb_intern("ceil") 01386 #define f_ceil(x) rb_funcall((x), id_ceil, 0) 01387 01388 #define id_quo rb_intern("quo") 01389 #define f_quo(x,y) rb_funcall((x), id_quo, 1, (y)) 01390 01391 #define f_reciprocal(x) f_quo(ONE, (x)) 01392 01393 /* 01394 The algorithm here is the method described in CLISP. Bruno Haible has 01395 graciously given permission to use this algorithm. He says, "You can use 01396 it, if you present the following explanation of the algorithm." 01397 01398 Algorithm (recursively presented): 01399 If x is a rational number, return x. 01400 If x = 0.0, return 0. 01401 If x < 0.0, return (- (rationalize (- x))). 01402 If x > 0.0: 01403 Call (integer-decode-float x). It returns a m,e,s=1 (mantissa, 01404 exponent, sign). 01405 If m = 0 or e >= 0: return x = m*2^e. 01406 Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e 01407 with smallest possible numerator and denominator. 01408 Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e. 01409 But in this case the result will be x itself anyway, regardless of 01410 the choice of a. Therefore we can simply ignore this case. 01411 Note 2: At first, we need to consider the closed interval [a,b]. 01412 but since a and b have the denominator 2^(|e|+1) whereas x itself 01413 has a denominator <= 2^|e|, we can restrict the search to the open 01414 interval (a,b). 01415 So, for given a and b (0 < a < b) we are searching a rational number 01416 y with a <= y <= b. 01417 Recursive algorithm fraction_between(a,b): 01418 c := (ceiling a) 01419 if c < b 01420 then return c ; because a <= c < b, c integer 01421 else 01422 ; a is not integer (otherwise we would have had c = a < b) 01423 k := c-1 ; k = floor(a), k < a < b <= k+1 01424 return y = k + 1/fraction_between(1/(b-k), 1/(a-k)) 01425 ; note 1 <= 1/(b-k) < 1/(a-k) 01426 01427 You can see that we are actually computing a continued fraction expansion. 01428 01429 Algorithm (iterative): 01430 If x is rational, return x. 01431 Call (integer-decode-float x). It returns a m,e,s (mantissa, 01432 exponent, sign). 01433 If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.) 01434 Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1) 01435 (positive and already in lowest terms because the denominator is a 01436 power of two and the numerator is odd). 01437 Start a continued fraction expansion 01438 p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0. 01439 Loop 01440 c := (ceiling a) 01441 if c >= b 01442 then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)), 01443 goto Loop 01444 finally partial_quotient(c). 01445 Here partial_quotient(c) denotes the iteration 01446 i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2]. 01447 At the end, return s * (p[i]/q[i]). 01448 This rational number is already in lowest terms because 01449 p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i. 01450 */ 01451 01452 static void 01453 nurat_rationalize_internal(VALUE a, VALUE b, VALUE *p, VALUE *q) 01454 { 01455 VALUE c, k, t, p0, p1, p2, q0, q1, q2; 01456 01457 p0 = ZERO; 01458 p1 = ONE; 01459 q0 = ONE; 01460 q1 = ZERO; 01461 01462 while (1) { 01463 c = f_ceil(a); 01464 if (f_lt_p(c, b)) 01465 break; 01466 k = f_sub(c, ONE); 01467 p2 = f_add(f_mul(k, p1), p0); 01468 q2 = f_add(f_mul(k, q1), q0); 01469 t = f_reciprocal(f_sub(b, k)); 01470 b = f_reciprocal(f_sub(a, k)); 01471 a = t; 01472 p0 = p1; 01473 q0 = q1; 01474 p1 = p2; 01475 q1 = q2; 01476 } 01477 *p = f_add(f_mul(c, p1), p0); 01478 *q = f_add(f_mul(c, q1), q0); 01479 } 01480 01481 /* 01482 * call-seq: 01483 * rat.rationalize -> self 01484 * rat.rationalize(eps) -> rational 01485 * 01486 * Returns a simpler approximation of the value if an optional 01487 * argument eps is given (rat-|eps| <= result <= rat+|eps|), self 01488 * otherwise. 01489 * 01490 * For example: 01491 * 01492 * r = Rational(5033165, 16777216) 01493 * r.rationalize #=> (5033165/16777216) 01494 * r.rationalize(Rational('0.01')) #=> (3/10) 01495 * r.rationalize(Rational('0.1')) #=> (1/3) 01496 */ 01497 static VALUE 01498 nurat_rationalize(int argc, VALUE *argv, VALUE self) 01499 { 01500 VALUE e, a, b, p, q; 01501 01502 if (argc == 0) 01503 return self; 01504 01505 if (f_negative_p(self)) 01506 return f_negate(nurat_rationalize(argc, argv, f_abs(self))); 01507 01508 rb_scan_args(argc, argv, "01", &e); 01509 e = f_abs(e); 01510 a = f_sub(self, e); 01511 b = f_add(self, e); 01512 01513 if (f_eqeq_p(a, b)) 01514 return self; 01515 01516 nurat_rationalize_internal(a, b, &p, &q); 01517 return f_rational_new2(CLASS_OF(self), p, q); 01518 } 01519 01520 /* :nodoc: */ 01521 static VALUE 01522 nurat_hash(VALUE self) 01523 { 01524 st_index_t v, h[2]; 01525 VALUE n; 01526 01527 get_dat1(self); 01528 n = rb_hash(dat->num); 01529 h[0] = NUM2LONG(n); 01530 n = rb_hash(dat->den); 01531 h[1] = NUM2LONG(n); 01532 v = rb_memhash(h, sizeof(h)); 01533 return LONG2FIX(v); 01534 } 01535 01536 static VALUE 01537 f_format(VALUE self, VALUE (*func)(VALUE)) 01538 { 01539 VALUE s; 01540 get_dat1(self); 01541 01542 s = (*func)(dat->num); 01543 rb_str_cat2(s, "/"); 01544 rb_str_concat(s, (*func)(dat->den)); 01545 01546 return s; 01547 } 01548 01549 /* 01550 * call-seq: 01551 * rat.to_s -> string 01552 * 01553 * Returns the value as a string. 01554 * 01555 * For example: 01556 * 01557 * Rational(2).to_s #=> "2/1" 01558 * Rational(-8, 6).to_s #=> "-4/3" 01559 * Rational('0.5').to_s #=> "1/2" 01560 */ 01561 static VALUE 01562 nurat_to_s(VALUE self) 01563 { 01564 return f_format(self, f_to_s); 01565 } 01566 01567 /* 01568 * call-seq: 01569 * rat.inspect -> string 01570 * 01571 * Returns the value as a string for inspection. 01572 * 01573 * For example: 01574 * 01575 * Rational(2).inspect #=> "(2/1)" 01576 * Rational(-8, 6).inspect #=> "(-4/3)" 01577 * Rational('0.5').inspect #=> "(1/2)" 01578 */ 01579 static VALUE 01580 nurat_inspect(VALUE self) 01581 { 01582 VALUE s; 01583 01584 s = rb_usascii_str_new2("("); 01585 rb_str_concat(s, f_format(self, f_inspect)); 01586 rb_str_cat2(s, ")"); 01587 01588 return s; 01589 } 01590 01591 /* :nodoc: */ 01592 static VALUE 01593 nurat_marshal_dump(VALUE self) 01594 { 01595 VALUE a; 01596 get_dat1(self); 01597 01598 a = rb_assoc_new(dat->num, dat->den); 01599 rb_copy_generic_ivar(a, self); 01600 return a; 01601 } 01602 01603 /* :nodoc: */ 01604 static VALUE 01605 nurat_marshal_load(VALUE self, VALUE a) 01606 { 01607 get_dat1(self); 01608 Check_Type(a, T_ARRAY); 01609 if (RARRAY_LEN(a) != 2) 01610 rb_raise(rb_eArgError, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a)); 01611 dat->num = RARRAY_PTR(a)[0]; 01612 dat->den = RARRAY_PTR(a)[1]; 01613 rb_copy_generic_ivar(self, a); 01614 01615 if (f_zero_p(dat->den)) 01616 rb_raise_zerodiv(); 01617 01618 return self; 01619 } 01620 01621 /* --- */ 01622 01623 VALUE 01624 rb_rational_reciprocal(VALUE x) 01625 { 01626 get_dat1(x); 01627 return f_rational_new_no_reduce2(CLASS_OF(x), dat->den, dat->num); 01628 } 01629 01630 /* 01631 * call-seq: 01632 * int.gcd(int2) -> integer 01633 * 01634 * Returns the greatest common divisor (always positive). 0.gcd(x) 01635 * and x.gcd(0) return abs(x). 01636 * 01637 * For example: 01638 * 01639 * 2.gcd(2) #=> 2 01640 * 3.gcd(-7) #=> 1 01641 * ((1<<31)-1).gcd((1<<61)-1) #=> 1 01642 */ 01643 VALUE 01644 rb_gcd(VALUE self, VALUE other) 01645 { 01646 other = nurat_int_value(other); 01647 return f_gcd(self, other); 01648 } 01649 01650 /* 01651 * call-seq: 01652 * int.lcm(int2) -> integer 01653 * 01654 * Returns the least common multiple (always positive). 0.lcm(x) and 01655 * x.lcm(0) return zero. 01656 * 01657 * For example: 01658 * 01659 * 2.lcm(2) #=> 2 01660 * 3.lcm(-7) #=> 21 01661 * ((1<<31)-1).lcm((1<<61)-1) #=> 4951760154835678088235319297 01662 */ 01663 VALUE 01664 rb_lcm(VALUE self, VALUE other) 01665 { 01666 other = nurat_int_value(other); 01667 return f_lcm(self, other); 01668 } 01669 01670 /* 01671 * call-seq: 01672 * int.gcdlcm(int2) -> array 01673 * 01674 * Returns an array; [int.gcd(int2), int.lcm(int2)]. 01675 * 01676 * For example: 01677 * 01678 * 2.gcdlcm(2) #=> [2, 2] 01679 * 3.gcdlcm(-7) #=> [1, 21] 01680 * ((1<<31)-1).gcdlcm((1<<61)-1) #=> [1, 4951760154835678088235319297] 01681 */ 01682 VALUE 01683 rb_gcdlcm(VALUE self, VALUE other) 01684 { 01685 other = nurat_int_value(other); 01686 return rb_assoc_new(f_gcd(self, other), f_lcm(self, other)); 01687 } 01688 01689 VALUE 01690 rb_rational_raw(VALUE x, VALUE y) 01691 { 01692 return nurat_s_new_internal(rb_cRational, x, y); 01693 } 01694 01695 VALUE 01696 rb_rational_new(VALUE x, VALUE y) 01697 { 01698 return nurat_s_canonicalize_internal(rb_cRational, x, y); 01699 } 01700 01701 static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass); 01702 01703 VALUE 01704 rb_Rational(VALUE x, VALUE y) 01705 { 01706 VALUE a[2]; 01707 a[0] = x; 01708 a[1] = y; 01709 return nurat_s_convert(2, a, rb_cRational); 01710 } 01711 01712 #define id_numerator rb_intern("numerator") 01713 #define f_numerator(x) rb_funcall((x), id_numerator, 0) 01714 01715 #define id_denominator rb_intern("denominator") 01716 #define f_denominator(x) rb_funcall((x), id_denominator, 0) 01717 01718 #define id_to_r rb_intern("to_r") 01719 #define f_to_r(x) rb_funcall((x), id_to_r, 0) 01720 01721 /* 01722 * call-seq: 01723 * num.numerator -> integer 01724 * 01725 * Returns the numerator. 01726 */ 01727 static VALUE 01728 numeric_numerator(VALUE self) 01729 { 01730 return f_numerator(f_to_r(self)); 01731 } 01732 01733 /* 01734 * call-seq: 01735 * num.denominator -> integer 01736 * 01737 * Returns the denominator (always positive). 01738 */ 01739 static VALUE 01740 numeric_denominator(VALUE self) 01741 { 01742 return f_denominator(f_to_r(self)); 01743 } 01744 01745 /* 01746 * call-seq: 01747 * int.numerator -> self 01748 * 01749 * Returns self. 01750 */ 01751 static VALUE 01752 integer_numerator(VALUE self) 01753 { 01754 return self; 01755 } 01756 01757 /* 01758 * call-seq: 01759 * int.denominator -> 1 01760 * 01761 * Returns 1. 01762 */ 01763 static VALUE 01764 integer_denominator(VALUE self) 01765 { 01766 return INT2FIX(1); 01767 } 01768 01769 /* 01770 * call-seq: 01771 * flo.numerator -> integer 01772 * 01773 * Returns the numerator. The result is machine dependent. 01774 * 01775 * For example: 01776 * 01777 * n = 0.3.numerator #=> 5404319552844595 01778 * d = 0.3.denominator #=> 18014398509481984 01779 * n.fdiv(d) #=> 0.3 01780 */ 01781 static VALUE 01782 float_numerator(VALUE self) 01783 { 01784 double d = RFLOAT_VALUE(self); 01785 if (isinf(d) || isnan(d)) 01786 return self; 01787 return rb_call_super(0, 0); 01788 } 01789 01790 /* 01791 * call-seq: 01792 * flo.denominator -> integer 01793 * 01794 * Returns the denominator (always positive). The result is machine 01795 * dependent. 01796 * 01797 * See numerator. 01798 */ 01799 static VALUE 01800 float_denominator(VALUE self) 01801 { 01802 double d = RFLOAT_VALUE(self); 01803 if (isinf(d) || isnan(d)) 01804 return INT2FIX(1); 01805 return rb_call_super(0, 0); 01806 } 01807 01808 /* 01809 * call-seq: 01810 * nil.to_r -> (0/1) 01811 * 01812 * Returns zero as a rational. 01813 */ 01814 static VALUE 01815 nilclass_to_r(VALUE self) 01816 { 01817 return rb_rational_new1(INT2FIX(0)); 01818 } 01819 01820 /* 01821 * call-seq: 01822 * nil.rationalize([eps]) -> (0/1) 01823 * 01824 * Returns zero as a rational. An optional argument eps is always 01825 * ignored. 01826 */ 01827 static VALUE 01828 nilclass_rationalize(int argc, VALUE *argv, VALUE self) 01829 { 01830 rb_scan_args(argc, argv, "01", NULL); 01831 return nilclass_to_r(self); 01832 } 01833 01834 /* 01835 * call-seq: 01836 * int.to_r -> rational 01837 * 01838 * Returns the value as a rational. 01839 * 01840 * For example: 01841 * 01842 * 1.to_r #=> (1/1) 01843 * (1<<64).to_r #=> (18446744073709551616/1) 01844 */ 01845 static VALUE 01846 integer_to_r(VALUE self) 01847 { 01848 return rb_rational_new1(self); 01849 } 01850 01851 /* 01852 * call-seq: 01853 * int.rationalize([eps]) -> rational 01854 * 01855 * Returns the value as a rational. An optional argument eps is 01856 * always ignored. 01857 */ 01858 static VALUE 01859 integer_rationalize(int argc, VALUE *argv, VALUE self) 01860 { 01861 rb_scan_args(argc, argv, "01", NULL); 01862 return integer_to_r(self); 01863 } 01864 01865 static void 01866 float_decode_internal(VALUE self, VALUE *rf, VALUE *rn) 01867 { 01868 double f; 01869 int n; 01870 01871 f = frexp(RFLOAT_VALUE(self), &n); 01872 f = ldexp(f, DBL_MANT_DIG); 01873 n -= DBL_MANT_DIG; 01874 *rf = rb_dbl2big(f); 01875 *rn = INT2FIX(n); 01876 } 01877 01878 #if 0 01879 static VALUE 01880 float_decode(VALUE self) 01881 { 01882 VALUE f, n; 01883 01884 float_decode_internal(self, &f, &n); 01885 return rb_assoc_new(f, n); 01886 } 01887 #endif 01888 01889 #define id_lshift rb_intern("<<") 01890 #define f_lshift(x,n) rb_funcall((x), id_lshift, 1, (n)) 01891 01892 /* 01893 * call-seq: 01894 * flt.to_r -> rational 01895 * 01896 * Returns the value as a rational. 01897 * 01898 * NOTE: 0.3.to_r isn't the same as '0.3'.to_r. The latter is 01899 * equivalent to '3/10'.to_r, but the former isn't so. 01900 * 01901 * For example: 01902 * 01903 * 2.0.to_r #=> (2/1) 01904 * 2.5.to_r #=> (5/2) 01905 * -0.75.to_r #=> (-3/4) 01906 * 0.0.to_r #=> (0/1) 01907 */ 01908 static VALUE 01909 float_to_r(VALUE self) 01910 { 01911 VALUE f, n; 01912 01913 float_decode_internal(self, &f, &n); 01914 #if FLT_RADIX == 2 01915 { 01916 long ln = FIX2LONG(n); 01917 01918 if (ln == 0) 01919 return f_to_r(f); 01920 if (ln > 0) 01921 return f_to_r(f_lshift(f, n)); 01922 ln = -ln; 01923 return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln))); 01924 } 01925 #else 01926 return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n))); 01927 #endif 01928 } 01929 01930 /* 01931 * call-seq: 01932 * flt.rationalize([eps]) -> rational 01933 * 01934 * Returns a simpler approximation of the value (flt-|eps| <= result 01935 * <= flt+|eps|). if eps is not given, it will be chosen 01936 * automatically. 01937 * 01938 * For example: 01939 * 01940 * 0.3.rationalize #=> (3/10) 01941 * 1.333.rationalize #=> (1333/1000) 01942 * 1.333.rationalize(0.01) #=> (4/3) 01943 */ 01944 static VALUE 01945 float_rationalize(int argc, VALUE *argv, VALUE self) 01946 { 01947 VALUE e, a, b, p, q; 01948 01949 if (f_negative_p(self)) 01950 return f_negate(float_rationalize(argc, argv, f_abs(self))); 01951 01952 rb_scan_args(argc, argv, "01", &e); 01953 01954 if (argc != 0) { 01955 e = f_abs(e); 01956 a = f_sub(self, e); 01957 b = f_add(self, e); 01958 } 01959 else { 01960 VALUE f, n; 01961 01962 float_decode_internal(self, &f, &n); 01963 if (f_zero_p(f) || f_positive_p(n)) 01964 return rb_rational_new1(f_lshift(f, n)); 01965 01966 #if FLT_RADIX == 2 01967 a = rb_rational_new2(f_sub(f_mul(TWO, f), ONE), 01968 f_lshift(ONE, f_sub(ONE, n))); 01969 b = rb_rational_new2(f_add(f_mul(TWO, f), ONE), 01970 f_lshift(ONE, f_sub(ONE, n))); 01971 #else 01972 a = rb_rational_new2(f_sub(f_mul(INT2FIX(FLT_RADIX), f), 01973 INT2FIX(FLT_RADIX - 1)), 01974 f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n))); 01975 b = rb_rational_new2(f_add(f_mul(INT2FIX(FLT_RADIX), f), 01976 INT2FIX(FLT_RADIX - 1)), 01977 f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n))); 01978 #endif 01979 } 01980 01981 if (f_eqeq_p(a, b)) 01982 return f_to_r(self); 01983 01984 nurat_rationalize_internal(a, b, &p, &q); 01985 return rb_rational_new2(p, q); 01986 } 01987 01988 static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore; 01989 01990 #define WS "\\s*" 01991 #define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)" 01992 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?" 01993 #define DENOMINATOR DIGITS 01994 #define PATTERN "\\A" WS "([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?" WS 01995 01996 static void 01997 make_patterns(void) 01998 { 01999 static const char rat_pat_source[] = PATTERN; 02000 static const char an_e_pat_source[] = "[eE]"; 02001 static const char a_dot_pat_source[] = "\\."; 02002 static const char underscores_pat_source[] = "_+"; 02003 02004 if (rat_pat) return; 02005 02006 rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0); 02007 rb_gc_register_mark_object(rat_pat); 02008 02009 an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0); 02010 rb_gc_register_mark_object(an_e_pat); 02011 02012 a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0); 02013 rb_gc_register_mark_object(a_dot_pat); 02014 02015 underscores_pat = rb_reg_new(underscores_pat_source, 02016 sizeof underscores_pat_source - 1, 0); 02017 rb_gc_register_mark_object(underscores_pat); 02018 02019 an_underscore = rb_usascii_str_new2("_"); 02020 rb_gc_register_mark_object(an_underscore); 02021 } 02022 02023 #define id_match rb_intern("match") 02024 #define f_match(x,y) rb_funcall((x), id_match, 1, (y)) 02025 02026 #define id_split rb_intern("split") 02027 #define f_split(x,y) rb_funcall((x), id_split, 1, (y)) 02028 02029 #include <ctype.h> 02030 02031 static VALUE 02032 string_to_r_internal(VALUE self) 02033 { 02034 VALUE s, m; 02035 02036 s = self; 02037 02038 if (RSTRING_LEN(s) == 0) 02039 return rb_assoc_new(Qnil, self); 02040 02041 m = f_match(rat_pat, s); 02042 02043 if (!NIL_P(m)) { 02044 VALUE v, ifp, exp, ip, fp; 02045 VALUE si = rb_reg_nth_match(1, m); 02046 VALUE nu = rb_reg_nth_match(2, m); 02047 VALUE de = rb_reg_nth_match(3, m); 02048 VALUE re = rb_reg_match_post(m); 02049 02050 { 02051 VALUE a; 02052 02053 if (!strpbrk(RSTRING_PTR(nu), "eE")) { 02054 ifp = nu; /* not a copy */ 02055 exp = Qnil; 02056 } 02057 else { 02058 a = f_split(nu, an_e_pat); 02059 ifp = RARRAY_PTR(a)[0]; 02060 if (RARRAY_LEN(a) != 2) 02061 exp = Qnil; 02062 else 02063 exp = RARRAY_PTR(a)[1]; 02064 } 02065 02066 if (!strchr(RSTRING_PTR(ifp), '.')) { 02067 ip = ifp; /* not a copy */ 02068 fp = Qnil; 02069 } 02070 else { 02071 a = f_split(ifp, a_dot_pat); 02072 ip = RARRAY_PTR(a)[0]; 02073 if (RARRAY_LEN(a) != 2) 02074 fp = Qnil; 02075 else 02076 fp = RARRAY_PTR(a)[1]; 02077 } 02078 } 02079 02080 v = rb_rational_new1(f_to_i(ip)); 02081 02082 if (!NIL_P(fp)) { 02083 char *p = RSTRING_PTR(fp); 02084 long count = 0; 02085 VALUE l; 02086 02087 while (*p) { 02088 if (rb_isdigit(*p)) 02089 count++; 02090 p++; 02091 } 02092 l = f_expt10(LONG2NUM(count)); 02093 v = f_mul(v, l); 02094 v = f_add(v, f_to_i(fp)); 02095 v = f_div(v, l); 02096 } 02097 if (!NIL_P(si) && *RSTRING_PTR(si) == '-') 02098 v = f_negate(v); 02099 if (!NIL_P(exp)) 02100 v = f_mul(v, f_expt10(f_to_i(exp))); 02101 #if 0 02102 if (!NIL_P(de) && (!NIL_P(fp) || !NIL_P(exp))) 02103 return rb_assoc_new(v, rb_usascii_str_new2("dummy")); 02104 #endif 02105 if (!NIL_P(de)) 02106 v = f_div(v, f_to_i(de)); 02107 02108 return rb_assoc_new(v, re); 02109 } 02110 return rb_assoc_new(Qnil, self); 02111 } 02112 02113 static VALUE 02114 string_to_r_strict(VALUE self) 02115 { 02116 VALUE a = string_to_r_internal(self); 02117 if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) { 02118 VALUE s = f_inspect(self); 02119 rb_raise(rb_eArgError, "invalid value for convert(): %s", 02120 StringValuePtr(s)); 02121 } 02122 return RARRAY_PTR(a)[0]; 02123 } 02124 02125 #define id_gsub rb_intern("gsub") 02126 #define f_gsub(x,y,z) rb_funcall((x), id_gsub, 2, (y), (z)) 02127 02128 /* 02129 * call-seq: 02130 * str.to_r -> rational 02131 * 02132 * Returns a rational which denotes the string form. The parser 02133 * ignores leading whitespaces and trailing garbage. Any digit 02134 * sequences can be separated by an underscore. Returns zero for null 02135 * or garbage string. 02136 * 02137 * NOTE: '0.3'.to_r isn't the same as 0.3.to_r. The former is 02138 * equivalent to '3/10'.to_r, but the latter isn't so. 02139 * 02140 * For example: 02141 * 02142 * ' 2 '.to_r #=> (2/1) 02143 * '300/2'.to_r #=> (150/1) 02144 * '-9.2'.to_r #=> (-46/5) 02145 * '-9.2e2'.to_r #=> (-920/1) 02146 * '1_234_567'.to_r #=> (1234567/1) 02147 * '21 june 09'.to_r #=> (21/1) 02148 * '21/06/09'.to_r #=> (7/2) 02149 * 'bwv 1079'.to_r #=> (0/1) 02150 */ 02151 static VALUE 02152 string_to_r(VALUE self) 02153 { 02154 VALUE s, a, a1, backref; 02155 02156 backref = rb_backref_get(); 02157 rb_match_busy(backref); 02158 02159 s = f_gsub(self, underscores_pat, an_underscore); 02160 a = string_to_r_internal(s); 02161 02162 rb_backref_set(backref); 02163 02164 a1 = RARRAY_PTR(a)[0]; 02165 if (!NIL_P(a1)) { 02166 if (TYPE(a1) == T_FLOAT) 02167 rb_raise(rb_eFloatDomainError, "Infinity"); 02168 return a1; 02169 } 02170 return rb_rational_new1(INT2FIX(0)); 02171 } 02172 02173 #define id_to_r rb_intern("to_r") 02174 #define f_to_r(x) rb_funcall((x), id_to_r, 0) 02175 02176 static VALUE 02177 nurat_s_convert(int argc, VALUE *argv, VALUE klass) 02178 { 02179 VALUE a1, a2, backref; 02180 02181 rb_scan_args(argc, argv, "11", &a1, &a2); 02182 02183 if (NIL_P(a1) || (argc == 2 && NIL_P(a2))) 02184 rb_raise(rb_eTypeError, "can't convert nil into Rational"); 02185 02186 switch (TYPE(a1)) { 02187 case T_COMPLEX: 02188 if (k_exact_zero_p(RCOMPLEX(a1)->imag)) 02189 a1 = RCOMPLEX(a1)->real; 02190 } 02191 02192 switch (TYPE(a2)) { 02193 case T_COMPLEX: 02194 if (k_exact_zero_p(RCOMPLEX(a2)->imag)) 02195 a2 = RCOMPLEX(a2)->real; 02196 } 02197 02198 backref = rb_backref_get(); 02199 rb_match_busy(backref); 02200 02201 switch (TYPE(a1)) { 02202 case T_FIXNUM: 02203 case T_BIGNUM: 02204 break; 02205 case T_FLOAT: 02206 a1 = f_to_r(a1); 02207 break; 02208 case T_STRING: 02209 a1 = string_to_r_strict(a1); 02210 break; 02211 } 02212 02213 switch (TYPE(a2)) { 02214 case T_FIXNUM: 02215 case T_BIGNUM: 02216 break; 02217 case T_FLOAT: 02218 a2 = f_to_r(a2); 02219 break; 02220 case T_STRING: 02221 a2 = string_to_r_strict(a2); 02222 break; 02223 } 02224 02225 rb_backref_set(backref); 02226 02227 switch (TYPE(a1)) { 02228 case T_RATIONAL: 02229 if (argc == 1 || (k_exact_one_p(a2))) 02230 return a1; 02231 } 02232 02233 if (argc == 1) { 02234 if (!(k_numeric_p(a1) && k_integer_p(a1))) 02235 return rb_convert_type(a1, T_RATIONAL, "Rational", "to_r"); 02236 } 02237 else { 02238 if ((k_numeric_p(a1) && k_numeric_p(a2)) && 02239 (!f_integer_p(a1) || !f_integer_p(a2))) 02240 return f_div(a1, a2); 02241 } 02242 02243 { 02244 VALUE argv2[2]; 02245 argv2[0] = a1; 02246 argv2[1] = a2; 02247 return nurat_s_new(argc, argv2, klass); 02248 } 02249 } 02250 02251 /* 02252 * A rational number can be represented as a paired integer number; 02253 * a/b (b>0). Where a is numerator and b is denominator. Integer a 02254 * equals rational a/1 mathematically. 02255 * 02256 * In ruby, you can create rational object with Rational, to_r or 02257 * rationalize method. The return values will be irreducible. 02258 * 02259 * Rational(1) #=> (1/1) 02260 * Rational(2, 3) #=> (2/3) 02261 * Rational(4, -6) #=> (-2/3) 02262 * 3.to_r #=> (3/1) 02263 * 02264 * You can also create rational object from floating-point numbers or 02265 * strings. 02266 * 02267 * Rational(0.3) #=> (5404319552844595/18014398509481984) 02268 * Rational('0.3') #=> (3/10) 02269 * Rational('2/3') #=> (2/3) 02270 * 02271 * 0.3.to_r #=> (5404319552844595/18014398509481984) 02272 * '0.3'.to_r #=> (3/10) 02273 * '2/3'.to_r #=> (2/3) 02274 * 0.3.rationalize #=> (3/10) 02275 * 02276 * A rational object is an exact number, which helps you to write 02277 * program without any rounding errors. 02278 * 02279 * 10.times.inject(0){|t,| t + 0.1} #=> 0.9999999999999999 02280 * 10.times.inject(0){|t,| t + Rational('0.1')} #=> (1/1) 02281 * 02282 * However, when an expression has inexact factor (numerical value or 02283 * operation), will produce an inexact result. 02284 * 02285 * Rational(10) / 3 #=> (10/3) 02286 * Rational(10) / 3.0 #=> 3.3333333333333335 02287 * 02288 * Rational(-8) ** Rational(1, 3) 02289 * #=> (1.0000000000000002+1.7320508075688772i) 02290 */ 02291 void 02292 Init_Rational(void) 02293 { 02294 #undef rb_intern 02295 #define rb_intern(str) rb_intern_const(str) 02296 02297 assert(fprintf(stderr, "assert() is now active\n")); 02298 02299 id_abs = rb_intern("abs"); 02300 id_cmp = rb_intern("<=>"); 02301 id_convert = rb_intern("convert"); 02302 id_eqeq_p = rb_intern("=="); 02303 id_expt = rb_intern("**"); 02304 id_fdiv = rb_intern("fdiv"); 02305 id_floor = rb_intern("floor"); 02306 id_idiv = rb_intern("div"); 02307 id_inspect = rb_intern("inspect"); 02308 id_integer_p = rb_intern("integer?"); 02309 id_negate = rb_intern("-@"); 02310 id_to_f = rb_intern("to_f"); 02311 id_to_i = rb_intern("to_i"); 02312 id_to_s = rb_intern("to_s"); 02313 id_truncate = rb_intern("truncate"); 02314 02315 rb_cRational = rb_define_class("Rational", rb_cNumeric); 02316 02317 rb_define_alloc_func(rb_cRational, nurat_s_alloc); 02318 rb_undef_method(CLASS_OF(rb_cRational), "allocate"); 02319 02320 #if 0 02321 rb_define_private_method(CLASS_OF(rb_cRational), "new!", nurat_s_new_bang, -1); 02322 rb_define_private_method(CLASS_OF(rb_cRational), "new", nurat_s_new, -1); 02323 #else 02324 rb_undef_method(CLASS_OF(rb_cRational), "new"); 02325 #endif 02326 02327 rb_define_global_function("Rational", nurat_f_rational, -1); 02328 02329 rb_define_method(rb_cRational, "numerator", nurat_numerator, 0); 02330 rb_define_method(rb_cRational, "denominator", nurat_denominator, 0); 02331 02332 rb_define_method(rb_cRational, "+", nurat_add, 1); 02333 rb_define_method(rb_cRational, "-", nurat_sub, 1); 02334 rb_define_method(rb_cRational, "*", nurat_mul, 1); 02335 rb_define_method(rb_cRational, "/", nurat_div, 1); 02336 rb_define_method(rb_cRational, "quo", nurat_div, 1); 02337 rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1); 02338 rb_define_method(rb_cRational, "**", nurat_expt, 1); 02339 02340 rb_define_method(rb_cRational, "<=>", nurat_cmp, 1); 02341 rb_define_method(rb_cRational, "==", nurat_eqeq_p, 1); 02342 rb_define_method(rb_cRational, "coerce", nurat_coerce, 1); 02343 02344 #if 0 /* NUBY */ 02345 rb_define_method(rb_cRational, "//", nurat_idiv, 1); 02346 #endif 02347 02348 #if 0 02349 rb_define_method(rb_cRational, "quot", nurat_quot, 1); 02350 rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1); 02351 #endif 02352 02353 #if 0 02354 rb_define_method(rb_cRational, "rational?", nurat_true, 0); 02355 rb_define_method(rb_cRational, "exact?", nurat_true, 0); 02356 #endif 02357 02358 rb_define_method(rb_cRational, "floor", nurat_floor_n, -1); 02359 rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1); 02360 rb_define_method(rb_cRational, "truncate", nurat_truncate_n, -1); 02361 rb_define_method(rb_cRational, "round", nurat_round_n, -1); 02362 02363 rb_define_method(rb_cRational, "to_i", nurat_truncate, 0); 02364 rb_define_method(rb_cRational, "to_f", nurat_to_f, 0); 02365 rb_define_method(rb_cRational, "to_r", nurat_to_r, 0); 02366 rb_define_method(rb_cRational, "rationalize", nurat_rationalize, -1); 02367 02368 rb_define_method(rb_cRational, "hash", nurat_hash, 0); 02369 02370 rb_define_method(rb_cRational, "to_s", nurat_to_s, 0); 02371 rb_define_method(rb_cRational, "inspect", nurat_inspect, 0); 02372 02373 rb_define_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0); 02374 rb_define_method(rb_cRational, "marshal_load", nurat_marshal_load, 1); 02375 02376 /* --- */ 02377 02378 rb_define_method(rb_cInteger, "gcd", rb_gcd, 1); 02379 rb_define_method(rb_cInteger, "lcm", rb_lcm, 1); 02380 rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1); 02381 02382 rb_define_method(rb_cNumeric, "numerator", numeric_numerator, 0); 02383 rb_define_method(rb_cNumeric, "denominator", numeric_denominator, 0); 02384 02385 rb_define_method(rb_cInteger, "numerator", integer_numerator, 0); 02386 rb_define_method(rb_cInteger, "denominator", integer_denominator, 0); 02387 02388 rb_define_method(rb_cFloat, "numerator", float_numerator, 0); 02389 rb_define_method(rb_cFloat, "denominator", float_denominator, 0); 02390 02391 rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0); 02392 rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1); 02393 rb_define_method(rb_cInteger, "to_r", integer_to_r, 0); 02394 rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1); 02395 rb_define_method(rb_cFloat, "to_r", float_to_r, 0); 02396 rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1); 02397 02398 make_patterns(); 02399 02400 rb_define_method(rb_cString, "to_r", string_to_r, 0); 02401 02402 rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1); 02403 } 02404 02405 /* 02406 Local variables: 02407 c-file-style: "ruby" 02408 End: 02409 */ 02410