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