Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* 00002 rational.c: Coded by Tadayoshi Funaba 2008-2012 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, id_i_num, id_i_den; 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) || RB_TYPE_P(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) || RB_TYPE_P(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 (RB_TYPE_P(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 (RB_TYPE_P(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_minus_one_p(VALUE x) 00225 { 00226 switch (TYPE(x)) { 00227 case T_FIXNUM: 00228 return f_boolcast(FIX2LONG(x) == -1); 00229 case T_BIGNUM: 00230 return Qfalse; 00231 case T_RATIONAL: 00232 { 00233 VALUE num = RRATIONAL(x)->num; 00234 VALUE den = RRATIONAL(x)->den; 00235 00236 return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == -1 && 00237 FIXNUM_P(den) && FIX2LONG(den) == 1); 00238 } 00239 } 00240 return rb_funcall(x, id_eqeq_p, 1, INT2FIX(-1)); 00241 } 00242 00243 inline static VALUE 00244 f_kind_of_p(VALUE x, VALUE c) 00245 { 00246 return rb_obj_is_kind_of(x, c); 00247 } 00248 00249 inline static VALUE 00250 k_numeric_p(VALUE x) 00251 { 00252 return f_kind_of_p(x, rb_cNumeric); 00253 } 00254 00255 inline static VALUE 00256 k_integer_p(VALUE x) 00257 { 00258 return f_kind_of_p(x, rb_cInteger); 00259 } 00260 00261 inline static VALUE 00262 k_float_p(VALUE x) 00263 { 00264 return f_kind_of_p(x, rb_cFloat); 00265 } 00266 00267 inline static VALUE 00268 k_rational_p(VALUE x) 00269 { 00270 return f_kind_of_p(x, rb_cRational); 00271 } 00272 00273 #define k_exact_p(x) (!k_float_p(x)) 00274 #define k_inexact_p(x) k_float_p(x) 00275 00276 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x)) 00277 #define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x)) 00278 00279 #ifndef NDEBUG 00280 #define f_gcd f_gcd_orig 00281 #endif 00282 00283 inline static long 00284 i_gcd(long x, long y) 00285 { 00286 if (x < 0) 00287 x = -x; 00288 if (y < 0) 00289 y = -y; 00290 00291 if (x == 0) 00292 return y; 00293 if (y == 0) 00294 return x; 00295 00296 while (x > 0) { 00297 long t = x; 00298 x = y % x; 00299 y = t; 00300 } 00301 return y; 00302 } 00303 00304 inline static VALUE 00305 f_gcd(VALUE x, VALUE y) 00306 { 00307 VALUE z; 00308 00309 if (FIXNUM_P(x) && FIXNUM_P(y)) 00310 return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y))); 00311 00312 if (f_negative_p(x)) 00313 x = f_negate(x); 00314 if (f_negative_p(y)) 00315 y = f_negate(y); 00316 00317 if (f_zero_p(x)) 00318 return y; 00319 if (f_zero_p(y)) 00320 return x; 00321 00322 for (;;) { 00323 if (FIXNUM_P(x)) { 00324 if (FIX2LONG(x) == 0) 00325 return y; 00326 if (FIXNUM_P(y)) 00327 return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y))); 00328 } 00329 z = x; 00330 x = f_mod(y, x); 00331 y = z; 00332 } 00333 /* NOTREACHED */ 00334 } 00335 00336 #ifndef NDEBUG 00337 #undef f_gcd 00338 00339 inline static VALUE 00340 f_gcd(VALUE x, VALUE y) 00341 { 00342 VALUE r = f_gcd_orig(x, y); 00343 if (f_nonzero_p(r)) { 00344 assert(f_zero_p(f_mod(x, r))); 00345 assert(f_zero_p(f_mod(y, r))); 00346 } 00347 return r; 00348 } 00349 #endif 00350 00351 inline static VALUE 00352 f_lcm(VALUE x, VALUE y) 00353 { 00354 if (f_zero_p(x) || f_zero_p(y)) 00355 return ZERO; 00356 return f_abs(f_mul(f_div(x, f_gcd(x, y)), y)); 00357 } 00358 00359 #define get_dat1(x) \ 00360 struct RRational *dat;\ 00361 dat = ((struct RRational *)(x)) 00362 00363 #define get_dat2(x,y) \ 00364 struct RRational *adat, *bdat;\ 00365 adat = ((struct RRational *)(x));\ 00366 bdat = ((struct RRational *)(y)) 00367 00368 inline static VALUE 00369 nurat_s_new_internal(VALUE klass, VALUE num, VALUE den) 00370 { 00371 NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL); 00372 00373 obj->num = num; 00374 obj->den = den; 00375 00376 return (VALUE)obj; 00377 } 00378 00379 static VALUE 00380 nurat_s_alloc(VALUE klass) 00381 { 00382 return nurat_s_new_internal(klass, ZERO, ONE); 00383 } 00384 00385 #define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0") 00386 00387 #if 0 00388 static VALUE 00389 nurat_s_new_bang(int argc, VALUE *argv, VALUE klass) 00390 { 00391 VALUE num, den; 00392 00393 switch (rb_scan_args(argc, argv, "11", &num, &den)) { 00394 case 1: 00395 if (!k_integer_p(num)) 00396 num = f_to_i(num); 00397 den = ONE; 00398 break; 00399 default: 00400 if (!k_integer_p(num)) 00401 num = f_to_i(num); 00402 if (!k_integer_p(den)) 00403 den = f_to_i(den); 00404 00405 switch (FIX2INT(f_cmp(den, ZERO))) { 00406 case -1: 00407 num = f_negate(num); 00408 den = f_negate(den); 00409 break; 00410 case 0: 00411 rb_raise_zerodiv(); 00412 break; 00413 } 00414 break; 00415 } 00416 00417 return nurat_s_new_internal(klass, num, den); 00418 } 00419 #endif 00420 00421 inline static VALUE 00422 f_rational_new_bang1(VALUE klass, VALUE x) 00423 { 00424 return nurat_s_new_internal(klass, x, ONE); 00425 } 00426 00427 inline static VALUE 00428 f_rational_new_bang2(VALUE klass, VALUE x, VALUE y) 00429 { 00430 assert(f_positive_p(y)); 00431 assert(f_nonzero_p(y)); 00432 return nurat_s_new_internal(klass, x, y); 00433 } 00434 00435 #ifdef CANONICALIZATION_FOR_MATHN 00436 #define CANON 00437 #endif 00438 00439 #ifdef CANON 00440 static int canonicalization = 0; 00441 00442 RUBY_FUNC_EXPORTED void 00443 nurat_canonicalization(int f) 00444 { 00445 canonicalization = f; 00446 } 00447 #endif 00448 00449 inline static void 00450 nurat_int_check(VALUE num) 00451 { 00452 switch (TYPE(num)) { 00453 case T_FIXNUM: 00454 case T_BIGNUM: 00455 break; 00456 default: 00457 if (!k_numeric_p(num) || !f_integer_p(num)) 00458 rb_raise(rb_eTypeError, "not an integer"); 00459 } 00460 } 00461 00462 inline static VALUE 00463 nurat_int_value(VALUE num) 00464 { 00465 nurat_int_check(num); 00466 if (!k_integer_p(num)) 00467 num = f_to_i(num); 00468 return num; 00469 } 00470 00471 inline static VALUE 00472 nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den) 00473 { 00474 VALUE gcd; 00475 00476 switch (FIX2INT(f_cmp(den, ZERO))) { 00477 case -1: 00478 num = f_negate(num); 00479 den = f_negate(den); 00480 break; 00481 case 0: 00482 rb_raise_zerodiv(); 00483 break; 00484 } 00485 00486 gcd = f_gcd(num, den); 00487 num = f_idiv(num, gcd); 00488 den = f_idiv(den, gcd); 00489 00490 #ifdef CANON 00491 if (f_one_p(den) && canonicalization) 00492 return num; 00493 #endif 00494 return nurat_s_new_internal(klass, num, den); 00495 } 00496 00497 inline static VALUE 00498 nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den) 00499 { 00500 switch (FIX2INT(f_cmp(den, ZERO))) { 00501 case -1: 00502 num = f_negate(num); 00503 den = f_negate(den); 00504 break; 00505 case 0: 00506 rb_raise_zerodiv(); 00507 break; 00508 } 00509 00510 #ifdef CANON 00511 if (f_one_p(den) && canonicalization) 00512 return num; 00513 #endif 00514 return nurat_s_new_internal(klass, num, den); 00515 } 00516 00517 static VALUE 00518 nurat_s_new(int argc, VALUE *argv, VALUE klass) 00519 { 00520 VALUE num, den; 00521 00522 switch (rb_scan_args(argc, argv, "11", &num, &den)) { 00523 case 1: 00524 num = nurat_int_value(num); 00525 den = ONE; 00526 break; 00527 default: 00528 num = nurat_int_value(num); 00529 den = nurat_int_value(den); 00530 break; 00531 } 00532 00533 return nurat_s_canonicalize_internal(klass, num, den); 00534 } 00535 00536 inline static VALUE 00537 f_rational_new1(VALUE klass, VALUE x) 00538 { 00539 assert(!k_rational_p(x)); 00540 return nurat_s_canonicalize_internal(klass, x, ONE); 00541 } 00542 00543 inline static VALUE 00544 f_rational_new2(VALUE klass, VALUE x, VALUE y) 00545 { 00546 assert(!k_rational_p(x)); 00547 assert(!k_rational_p(y)); 00548 return nurat_s_canonicalize_internal(klass, x, y); 00549 } 00550 00551 inline static VALUE 00552 f_rational_new_no_reduce1(VALUE klass, VALUE x) 00553 { 00554 assert(!k_rational_p(x)); 00555 return nurat_s_canonicalize_internal_no_reduce(klass, x, ONE); 00556 } 00557 00558 inline static VALUE 00559 f_rational_new_no_reduce2(VALUE klass, VALUE x, VALUE y) 00560 { 00561 assert(!k_rational_p(x)); 00562 assert(!k_rational_p(y)); 00563 return nurat_s_canonicalize_internal_no_reduce(klass, x, y); 00564 } 00565 00566 /* 00567 * call-seq: 00568 * Rational(x[, y]) -> numeric 00569 * 00570 * Returns x/y; 00571 * 00572 * Rational(1, 2) #=> (1/2) 00573 * Rational('1/2') #=> (1/2) 00574 * 00575 * Syntax of string form: 00576 * 00577 * string form = extra spaces , rational , extra spaces ; 00578 * rational = [ sign ] , unsigned rational ; 00579 * unsigned rational = numerator | numerator , "/" , denominator ; 00580 * numerator = integer part | fractional part | integer part , fractional part ; 00581 * denominator = digits ; 00582 * integer part = digits ; 00583 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ; 00584 * sign = "-" | "+" ; 00585 * digits = digit , { digit | "_" , digit } ; 00586 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; 00587 * extra spaces = ? \s* ? ; 00588 * 00589 * See String#to_r. 00590 */ 00591 static VALUE 00592 nurat_f_rational(int argc, VALUE *argv, VALUE klass) 00593 { 00594 return rb_funcall2(rb_cRational, id_convert, argc, argv); 00595 } 00596 00597 /* 00598 * call-seq: 00599 * rat.numerator -> integer 00600 * 00601 * Returns the numerator. 00602 * 00603 * Rational(7).numerator #=> 7 00604 * Rational(7, 1).numerator #=> 7 00605 * Rational(9, -4).numerator #=> -9 00606 * Rational(-2, -10).numerator #=> 1 00607 */ 00608 static VALUE 00609 nurat_numerator(VALUE self) 00610 { 00611 get_dat1(self); 00612 return dat->num; 00613 } 00614 00615 /* 00616 * call-seq: 00617 * rat.denominator -> integer 00618 * 00619 * Returns the denominator (always positive). 00620 * 00621 * Rational(7).denominator #=> 1 00622 * Rational(7, 1).denominator #=> 1 00623 * Rational(9, -4).denominator #=> 4 00624 * Rational(-2, -10).denominator #=> 5 00625 * rat.numerator.gcd(rat.denominator) #=> 1 00626 */ 00627 static VALUE 00628 nurat_denominator(VALUE self) 00629 { 00630 get_dat1(self); 00631 return dat->den; 00632 } 00633 00634 #ifndef NDEBUG 00635 #define f_imul f_imul_orig 00636 #endif 00637 00638 inline static VALUE 00639 f_imul(long a, long b) 00640 { 00641 VALUE r; 00642 00643 if (a == 0 || b == 0) 00644 return ZERO; 00645 else if (a == 1) 00646 return LONG2NUM(b); 00647 else if (b == 1) 00648 return LONG2NUM(a); 00649 00650 if (MUL_OVERFLOW_LONG_P(a, b)) 00651 r = rb_big_mul(rb_int2big(a), rb_int2big(b)); 00652 else 00653 r = LONG2NUM(a * b); 00654 return r; 00655 } 00656 00657 #ifndef NDEBUG 00658 #undef f_imul 00659 00660 inline static VALUE 00661 f_imul(long x, long y) 00662 { 00663 VALUE r = f_imul_orig(x, y); 00664 assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y)))); 00665 return r; 00666 } 00667 #endif 00668 00669 inline static VALUE 00670 f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) 00671 { 00672 VALUE num, den; 00673 00674 if (FIXNUM_P(anum) && FIXNUM_P(aden) && 00675 FIXNUM_P(bnum) && FIXNUM_P(bden)) { 00676 long an = FIX2LONG(anum); 00677 long ad = FIX2LONG(aden); 00678 long bn = FIX2LONG(bnum); 00679 long bd = FIX2LONG(bden); 00680 long ig = i_gcd(ad, bd); 00681 00682 VALUE g = LONG2NUM(ig); 00683 VALUE a = f_imul(an, bd / ig); 00684 VALUE b = f_imul(bn, ad / ig); 00685 VALUE c; 00686 00687 if (k == '+') 00688 c = f_add(a, b); 00689 else 00690 c = f_sub(a, b); 00691 00692 b = f_idiv(aden, g); 00693 g = f_gcd(c, g); 00694 num = f_idiv(c, g); 00695 a = f_idiv(bden, g); 00696 den = f_mul(a, b); 00697 } 00698 else { 00699 VALUE g = f_gcd(aden, bden); 00700 VALUE a = f_mul(anum, f_idiv(bden, g)); 00701 VALUE b = f_mul(bnum, f_idiv(aden, g)); 00702 VALUE c; 00703 00704 if (k == '+') 00705 c = f_add(a, b); 00706 else 00707 c = f_sub(a, b); 00708 00709 b = f_idiv(aden, g); 00710 g = f_gcd(c, g); 00711 num = f_idiv(c, g); 00712 a = f_idiv(bden, g); 00713 den = f_mul(a, b); 00714 } 00715 return f_rational_new_no_reduce2(CLASS_OF(self), num, den); 00716 } 00717 00718 /* 00719 * call-seq: 00720 * rat + numeric -> numeric 00721 * 00722 * Performs addition. 00723 * 00724 * Rational(2, 3) + Rational(2, 3) #=> (4/3) 00725 * Rational(900) + Rational(1) #=> (900/1) 00726 * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18) 00727 * Rational(9, 8) + 4 #=> (41/8) 00728 * Rational(20, 9) + 9.8 #=> 12.022222222222222 00729 */ 00730 static VALUE 00731 nurat_add(VALUE self, VALUE other) 00732 { 00733 switch (TYPE(other)) { 00734 case T_FIXNUM: 00735 case T_BIGNUM: 00736 { 00737 get_dat1(self); 00738 00739 return f_addsub(self, 00740 dat->num, dat->den, 00741 other, ONE, '+'); 00742 } 00743 case T_FLOAT: 00744 return f_add(f_to_f(self), other); 00745 case T_RATIONAL: 00746 { 00747 get_dat2(self, other); 00748 00749 return f_addsub(self, 00750 adat->num, adat->den, 00751 bdat->num, bdat->den, '+'); 00752 } 00753 default: 00754 return rb_num_coerce_bin(self, other, '+'); 00755 } 00756 } 00757 00758 /* 00759 * call-seq: 00760 * rat - numeric -> numeric 00761 * 00762 * Performs subtraction. 00763 * 00764 * Rational(2, 3) - Rational(2, 3) #=> (0/1) 00765 * Rational(900) - Rational(1) #=> (899/1) 00766 * Rational(-2, 9) - Rational(-9, 2) #=> (77/18) 00767 * Rational(9, 8) - 4 #=> (23/8) 00768 * Rational(20, 9) - 9.8 #=> -7.577777777777778 00769 */ 00770 static VALUE 00771 nurat_sub(VALUE self, VALUE other) 00772 { 00773 switch (TYPE(other)) { 00774 case T_FIXNUM: 00775 case T_BIGNUM: 00776 { 00777 get_dat1(self); 00778 00779 return f_addsub(self, 00780 dat->num, dat->den, 00781 other, ONE, '-'); 00782 } 00783 case T_FLOAT: 00784 return f_sub(f_to_f(self), other); 00785 case T_RATIONAL: 00786 { 00787 get_dat2(self, other); 00788 00789 return f_addsub(self, 00790 adat->num, adat->den, 00791 bdat->num, bdat->den, '-'); 00792 } 00793 default: 00794 return rb_num_coerce_bin(self, other, '-'); 00795 } 00796 } 00797 00798 inline static VALUE 00799 f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) 00800 { 00801 VALUE num, den; 00802 00803 if (k == '/') { 00804 VALUE t; 00805 00806 if (f_negative_p(bnum)) { 00807 anum = f_negate(anum); 00808 bnum = f_negate(bnum); 00809 } 00810 t = bnum; 00811 bnum = bden; 00812 bden = t; 00813 } 00814 00815 if (FIXNUM_P(anum) && FIXNUM_P(aden) && 00816 FIXNUM_P(bnum) && FIXNUM_P(bden)) { 00817 long an = FIX2LONG(anum); 00818 long ad = FIX2LONG(aden); 00819 long bn = FIX2LONG(bnum); 00820 long bd = FIX2LONG(bden); 00821 long g1 = i_gcd(an, bd); 00822 long g2 = i_gcd(ad, bn); 00823 00824 num = f_imul(an / g1, bn / g2); 00825 den = f_imul(ad / g2, bd / g1); 00826 } 00827 else { 00828 VALUE g1 = f_gcd(anum, bden); 00829 VALUE g2 = f_gcd(aden, bnum); 00830 00831 num = f_mul(f_idiv(anum, g1), f_idiv(bnum, g2)); 00832 den = f_mul(f_idiv(aden, g2), f_idiv(bden, g1)); 00833 } 00834 return f_rational_new_no_reduce2(CLASS_OF(self), num, den); 00835 } 00836 00837 /* 00838 * call-seq: 00839 * rat * numeric -> numeric 00840 * 00841 * Performs multiplication. 00842 * 00843 * Rational(2, 3) * Rational(2, 3) #=> (4/9) 00844 * Rational(900) * Rational(1) #=> (900/1) 00845 * Rational(-2, 9) * Rational(-9, 2) #=> (1/1) 00846 * Rational(9, 8) * 4 #=> (9/2) 00847 * Rational(20, 9) * 9.8 #=> 21.77777777777778 00848 */ 00849 static VALUE 00850 nurat_mul(VALUE self, VALUE other) 00851 { 00852 switch (TYPE(other)) { 00853 case T_FIXNUM: 00854 case T_BIGNUM: 00855 { 00856 get_dat1(self); 00857 00858 return f_muldiv(self, 00859 dat->num, dat->den, 00860 other, ONE, '*'); 00861 } 00862 case T_FLOAT: 00863 return f_mul(f_to_f(self), other); 00864 case T_RATIONAL: 00865 { 00866 get_dat2(self, other); 00867 00868 return f_muldiv(self, 00869 adat->num, adat->den, 00870 bdat->num, bdat->den, '*'); 00871 } 00872 default: 00873 return rb_num_coerce_bin(self, other, '*'); 00874 } 00875 } 00876 00877 /* 00878 * call-seq: 00879 * rat / numeric -> numeric 00880 * rat.quo(numeric) -> numeric 00881 * 00882 * Performs division. 00883 * 00884 * Rational(2, 3) / Rational(2, 3) #=> (1/1) 00885 * Rational(900) / Rational(1) #=> (900/1) 00886 * Rational(-2, 9) / Rational(-9, 2) #=> (4/81) 00887 * Rational(9, 8) / 4 #=> (9/32) 00888 * Rational(20, 9) / 9.8 #=> 0.22675736961451246 00889 */ 00890 static VALUE 00891 nurat_div(VALUE self, VALUE other) 00892 { 00893 switch (TYPE(other)) { 00894 case T_FIXNUM: 00895 case T_BIGNUM: 00896 if (f_zero_p(other)) 00897 rb_raise_zerodiv(); 00898 { 00899 get_dat1(self); 00900 00901 return f_muldiv(self, 00902 dat->num, dat->den, 00903 other, ONE, '/'); 00904 } 00905 case T_FLOAT: 00906 { 00907 double x = RFLOAT_VALUE(other), den; 00908 get_dat1(self); 00909 00910 if (isnan(x)) return DBL2NUM(NAN); 00911 if (isinf(x)) return INT2FIX(0); 00912 if (x != 0.0 && modf(x, &den) == 0.0) { 00913 return rb_rational_raw2(dat->num, f_mul(rb_dbl2big(den), dat->den)); 00914 } 00915 } 00916 return rb_funcall(f_to_f(self), '/', 1, other); 00917 case T_RATIONAL: 00918 if (f_zero_p(other)) 00919 rb_raise_zerodiv(); 00920 { 00921 get_dat2(self, other); 00922 00923 if (f_one_p(self)) 00924 return f_rational_new_no_reduce2(CLASS_OF(self), 00925 bdat->den, bdat->num); 00926 00927 return f_muldiv(self, 00928 adat->num, adat->den, 00929 bdat->num, bdat->den, '/'); 00930 } 00931 default: 00932 return rb_num_coerce_bin(self, other, '/'); 00933 } 00934 } 00935 00936 /* 00937 * call-seq: 00938 * rat.fdiv(numeric) -> float 00939 * 00940 * Performs division and returns the value as a float. 00941 * 00942 * Rational(2, 3).fdiv(1) #=> 0.6666666666666666 00943 * Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333 00944 * Rational(2).fdiv(3) #=> 0.6666666666666666 00945 */ 00946 static VALUE 00947 nurat_fdiv(VALUE self, VALUE other) 00948 { 00949 if (f_zero_p(other)) 00950 return f_div(self, f_to_f(other)); 00951 return f_to_f(f_div(self, other)); 00952 } 00953 00954 inline static VALUE 00955 f_odd_p(VALUE integer) 00956 { 00957 if (rb_funcall(integer, '%', 1, INT2FIX(2)) != INT2FIX(0)) { 00958 return Qtrue; 00959 } 00960 return Qfalse; 00961 00962 } 00963 00964 /* 00965 * call-seq: 00966 * rat ** numeric -> numeric 00967 * 00968 * Performs exponentiation. 00969 * 00970 * Rational(2) ** Rational(3) #=> (8/1) 00971 * Rational(10) ** -2 #=> (1/100) 00972 * Rational(10) ** -2.0 #=> 0.01 00973 * Rational(-4) ** Rational(1,2) #=> (1.2246063538223773e-16+2.0i) 00974 * Rational(1, 2) ** 0 #=> (1/1) 00975 * Rational(1, 2) ** 0.0 #=> 1.0 00976 */ 00977 static VALUE 00978 nurat_expt(VALUE self, VALUE other) 00979 { 00980 if (k_numeric_p(other) && k_exact_zero_p(other)) 00981 return f_rational_new_bang1(CLASS_OF(self), ONE); 00982 00983 if (k_rational_p(other)) { 00984 get_dat1(other); 00985 00986 if (f_one_p(dat->den)) 00987 other = dat->num; /* c14n */ 00988 } 00989 00990 /* Deal with special cases of 0**n and 1**n */ 00991 if (k_numeric_p(other) && k_exact_p(other)) { 00992 get_dat1(self); 00993 if (f_one_p(dat->den)) 00994 if (f_one_p(dat->num)) 00995 return f_rational_new_bang1(CLASS_OF(self), ONE); 00996 else if (f_minus_one_p(dat->num) && k_integer_p(other)) 00997 return f_rational_new_bang1(CLASS_OF(self), INT2FIX(f_odd_p(other) ? -1 : 1)); 00998 else if (f_zero_p(dat->num)) 00999 if (FIX2INT(f_cmp(other, ZERO)) == -1) 01000 rb_raise_zerodiv(); 01001 else 01002 return f_rational_new_bang1(CLASS_OF(self), ZERO); 01003 } 01004 01005 /* General case */ 01006 switch (TYPE(other)) { 01007 case T_FIXNUM: 01008 { 01009 VALUE num, den; 01010 01011 get_dat1(self); 01012 01013 switch (FIX2INT(f_cmp(other, ZERO))) { 01014 case 1: 01015 num = f_expt(dat->num, other); 01016 den = f_expt(dat->den, other); 01017 break; 01018 case -1: 01019 num = f_expt(dat->den, f_negate(other)); 01020 den = f_expt(dat->num, f_negate(other)); 01021 break; 01022 default: 01023 num = ONE; 01024 den = ONE; 01025 break; 01026 } 01027 return f_rational_new2(CLASS_OF(self), num, den); 01028 } 01029 case T_BIGNUM: 01030 rb_warn("in a**b, b may be too big"); 01031 /* fall through */ 01032 case T_FLOAT: 01033 case T_RATIONAL: 01034 return f_expt(f_to_f(self), other); 01035 default: 01036 return rb_num_coerce_bin(self, other, id_expt); 01037 } 01038 } 01039 01040 /* 01041 * call-seq: 01042 * rational <=> numeric -> -1, 0, +1 or nil 01043 * 01044 * Performs comparison and returns -1, 0, or +1. 01045 * 01046 * +nil+ is returned if the two values are incomparable. 01047 * 01048 * Rational(2, 3) <=> Rational(2, 3) #=> 0 01049 * Rational(5) <=> 5 #=> 0 01050 * Rational(2,3) <=> Rational(1,3) #=> 1 01051 * Rational(1,3) <=> 1 #=> -1 01052 * Rational(1,3) <=> 0.3 #=> 1 01053 */ 01054 static VALUE 01055 nurat_cmp(VALUE self, VALUE other) 01056 { 01057 switch (TYPE(other)) { 01058 case T_FIXNUM: 01059 case T_BIGNUM: 01060 { 01061 get_dat1(self); 01062 01063 if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1) 01064 return f_cmp(dat->num, other); /* c14n */ 01065 return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other)); 01066 } 01067 case T_FLOAT: 01068 return f_cmp(f_to_f(self), other); 01069 case T_RATIONAL: 01070 { 01071 VALUE num1, num2; 01072 01073 get_dat2(self, other); 01074 01075 if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) && 01076 FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) { 01077 num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den)); 01078 num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den)); 01079 } 01080 else { 01081 num1 = f_mul(adat->num, bdat->den); 01082 num2 = f_mul(bdat->num, adat->den); 01083 } 01084 return f_cmp(f_sub(num1, num2), ZERO); 01085 } 01086 default: 01087 return rb_num_coerce_cmp(self, other, id_cmp); 01088 } 01089 } 01090 01091 /* 01092 * call-seq: 01093 * rat == object -> true or false 01094 * 01095 * Returns true if rat equals object numerically. 01096 * 01097 * Rational(2, 3) == Rational(2, 3) #=> true 01098 * Rational(5) == 5 #=> true 01099 * Rational(0) == 0.0 #=> true 01100 * Rational('1/3') == 0.33 #=> false 01101 * Rational('1/2') == '1/2' #=> false 01102 */ 01103 static VALUE 01104 nurat_eqeq_p(VALUE self, VALUE other) 01105 { 01106 switch (TYPE(other)) { 01107 case T_FIXNUM: 01108 case T_BIGNUM: 01109 { 01110 get_dat1(self); 01111 01112 if (f_zero_p(dat->num) && f_zero_p(other)) 01113 return Qtrue; 01114 01115 if (!FIXNUM_P(dat->den)) 01116 return Qfalse; 01117 if (FIX2LONG(dat->den) != 1) 01118 return Qfalse; 01119 if (f_eqeq_p(dat->num, other)) 01120 return Qtrue; 01121 return Qfalse; 01122 } 01123 case T_FLOAT: 01124 return f_eqeq_p(f_to_f(self), other); 01125 case T_RATIONAL: 01126 { 01127 get_dat2(self, other); 01128 01129 if (f_zero_p(adat->num) && f_zero_p(bdat->num)) 01130 return Qtrue; 01131 01132 return f_boolcast(f_eqeq_p(adat->num, bdat->num) && 01133 f_eqeq_p(adat->den, bdat->den)); 01134 } 01135 default: 01136 return f_eqeq_p(other, self); 01137 } 01138 } 01139 01140 /* :nodoc: */ 01141 static VALUE 01142 nurat_coerce(VALUE self, VALUE other) 01143 { 01144 switch (TYPE(other)) { 01145 case T_FIXNUM: 01146 case T_BIGNUM: 01147 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self); 01148 case T_FLOAT: 01149 return rb_assoc_new(other, f_to_f(self)); 01150 case T_RATIONAL: 01151 return rb_assoc_new(other, self); 01152 case T_COMPLEX: 01153 if (k_exact_zero_p(RCOMPLEX(other)->imag)) 01154 return rb_assoc_new(f_rational_new_bang1 01155 (CLASS_OF(self), RCOMPLEX(other)->real), self); 01156 else 01157 return rb_assoc_new(other, rb_Complex(self, INT2FIX(0))); 01158 } 01159 01160 rb_raise(rb_eTypeError, "%s can't be coerced into %s", 01161 rb_obj_classname(other), rb_obj_classname(self)); 01162 return Qnil; 01163 } 01164 01165 #if 0 01166 /* :nodoc: */ 01167 static VALUE 01168 nurat_idiv(VALUE self, VALUE other) 01169 { 01170 return f_idiv(self, other); 01171 } 01172 01173 /* :nodoc: */ 01174 static VALUE 01175 nurat_quot(VALUE self, VALUE other) 01176 { 01177 return f_truncate(f_div(self, other)); 01178 } 01179 01180 /* :nodoc: */ 01181 static VALUE 01182 nurat_quotrem(VALUE self, VALUE other) 01183 { 01184 VALUE val = f_truncate(f_div(self, other)); 01185 return rb_assoc_new(val, f_sub(self, f_mul(other, val))); 01186 } 01187 #endif 01188 01189 #if 0 01190 /* :nodoc: */ 01191 static VALUE 01192 nurat_true(VALUE self) 01193 { 01194 return Qtrue; 01195 } 01196 #endif 01197 01198 static VALUE 01199 nurat_floor(VALUE self) 01200 { 01201 get_dat1(self); 01202 return f_idiv(dat->num, dat->den); 01203 } 01204 01205 static VALUE 01206 nurat_ceil(VALUE self) 01207 { 01208 get_dat1(self); 01209 return f_negate(f_idiv(f_negate(dat->num), dat->den)); 01210 } 01211 01212 /* 01213 * call-seq: 01214 * rat.to_i -> integer 01215 * 01216 * Returns the truncated value as an integer. 01217 * 01218 * Equivalent to 01219 * rat.truncate. 01220 * 01221 * Rational(2, 3).to_i #=> 0 01222 * Rational(3).to_i #=> 3 01223 * Rational(300.6).to_i #=> 300 01224 * Rational(98,71).to_i #=> 1 01225 * Rational(-30,2).to_i #=> -15 01226 */ 01227 static VALUE 01228 nurat_truncate(VALUE self) 01229 { 01230 get_dat1(self); 01231 if (f_negative_p(dat->num)) 01232 return f_negate(f_idiv(f_negate(dat->num), dat->den)); 01233 return f_idiv(dat->num, dat->den); 01234 } 01235 01236 static VALUE 01237 nurat_round(VALUE self) 01238 { 01239 VALUE num, den, neg; 01240 01241 get_dat1(self); 01242 01243 num = dat->num; 01244 den = dat->den; 01245 neg = f_negative_p(num); 01246 01247 if (neg) 01248 num = f_negate(num); 01249 01250 num = f_add(f_mul(num, TWO), den); 01251 den = f_mul(den, TWO); 01252 num = f_idiv(num, den); 01253 01254 if (neg) 01255 num = f_negate(num); 01256 01257 return num; 01258 } 01259 01260 static VALUE 01261 f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE)) 01262 { 01263 VALUE n, b, s; 01264 01265 if (argc == 0) 01266 return (*func)(self); 01267 01268 rb_scan_args(argc, argv, "01", &n); 01269 01270 if (!k_integer_p(n)) 01271 rb_raise(rb_eTypeError, "not an integer"); 01272 01273 b = f_expt10(n); 01274 s = f_mul(self, b); 01275 01276 if (k_float_p(s)) { 01277 if (f_lt_p(n, ZERO)) 01278 return ZERO; 01279 return self; 01280 } 01281 01282 s = (*func)(s); 01283 01284 s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b); 01285 01286 if (f_lt_p(n, ONE)) 01287 s = f_to_i(s); 01288 01289 return s; 01290 } 01291 01292 /* 01293 * call-seq: 01294 * rat.floor -> integer 01295 * rat.floor(precision=0) -> rational 01296 * 01297 * Returns the truncated value (toward negative infinity). 01298 * 01299 * Rational(3).floor #=> 3 01300 * Rational(2, 3).floor #=> 0 01301 * Rational(-3, 2).floor #=> -1 01302 * 01303 * decimal - 1 2 3 . 4 5 6 01304 * ^ ^ ^ ^ ^ ^ 01305 * precision -3 -2 -1 0 +1 +2 01306 * 01307 * '%f' % Rational('-123.456').floor(+1) #=> "-123.500000" 01308 * '%f' % Rational('-123.456').floor(-1) #=> "-130.000000" 01309 */ 01310 static VALUE 01311 nurat_floor_n(int argc, VALUE *argv, VALUE self) 01312 { 01313 return f_round_common(argc, argv, self, nurat_floor); 01314 } 01315 01316 /* 01317 * call-seq: 01318 * rat.ceil -> integer 01319 * rat.ceil(precision=0) -> rational 01320 * 01321 * Returns the truncated value (toward positive infinity). 01322 * 01323 * Rational(3).ceil #=> 3 01324 * Rational(2, 3).ceil #=> 1 01325 * Rational(-3, 2).ceil #=> -1 01326 * 01327 * decimal - 1 2 3 . 4 5 6 01328 * ^ ^ ^ ^ ^ ^ 01329 * precision -3 -2 -1 0 +1 +2 01330 * 01331 * '%f' % Rational('-123.456').ceil(+1) #=> "-123.400000" 01332 * '%f' % Rational('-123.456').ceil(-1) #=> "-120.000000" 01333 */ 01334 static VALUE 01335 nurat_ceil_n(int argc, VALUE *argv, VALUE self) 01336 { 01337 return f_round_common(argc, argv, self, nurat_ceil); 01338 } 01339 01340 /* 01341 * call-seq: 01342 * rat.truncate -> integer 01343 * rat.truncate(precision=0) -> rational 01344 * 01345 * Returns the truncated value (toward zero). 01346 * 01347 * Rational(3).truncate #=> 3 01348 * Rational(2, 3).truncate #=> 0 01349 * Rational(-3, 2).truncate #=> -1 01350 * 01351 * decimal - 1 2 3 . 4 5 6 01352 * ^ ^ ^ ^ ^ ^ 01353 * precision -3 -2 -1 0 +1 +2 01354 * 01355 * '%f' % Rational('-123.456').truncate(+1) #=> "-123.400000" 01356 * '%f' % Rational('-123.456').truncate(-1) #=> "-120.000000" 01357 */ 01358 static VALUE 01359 nurat_truncate_n(int argc, VALUE *argv, VALUE self) 01360 { 01361 return f_round_common(argc, argv, self, nurat_truncate); 01362 } 01363 01364 /* 01365 * call-seq: 01366 * rat.round -> integer 01367 * rat.round(precision=0) -> rational 01368 * 01369 * Returns the truncated value (toward the nearest integer; 01370 * 0.5 => 1; -0.5 => -1). 01371 * 01372 * Rational(3).round #=> 3 01373 * Rational(2, 3).round #=> 1 01374 * Rational(-3, 2).round #=> -2 01375 * 01376 * decimal - 1 2 3 . 4 5 6 01377 * ^ ^ ^ ^ ^ ^ 01378 * precision -3 -2 -1 0 +1 +2 01379 * 01380 * '%f' % Rational('-123.456').round(+1) #=> "-123.500000" 01381 * '%f' % Rational('-123.456').round(-1) #=> "-120.000000" 01382 */ 01383 static VALUE 01384 nurat_round_n(int argc, VALUE *argv, VALUE self) 01385 { 01386 return f_round_common(argc, argv, self, nurat_round); 01387 } 01388 01389 /* 01390 * call-seq: 01391 * rat.to_f -> float 01392 * 01393 * Return the value as a float. 01394 * 01395 * Rational(2).to_f #=> 2.0 01396 * Rational(9, 4).to_f #=> 2.25 01397 * Rational(-3, 4).to_f #=> -0.75 01398 * Rational(20, 3).to_f #=> 6.666666666666667 01399 */ 01400 static VALUE 01401 nurat_to_f(VALUE self) 01402 { 01403 get_dat1(self); 01404 return f_fdiv(dat->num, dat->den); 01405 } 01406 01407 /* 01408 * call-seq: 01409 * rat.to_r -> self 01410 * 01411 * Returns self. 01412 * 01413 * Rational(2).to_r #=> (2/1) 01414 * Rational(-8, 6).to_r #=> (-4/3) 01415 */ 01416 static VALUE 01417 nurat_to_r(VALUE self) 01418 { 01419 return self; 01420 } 01421 01422 #define id_ceil rb_intern("ceil") 01423 #define f_ceil(x) rb_funcall((x), id_ceil, 0) 01424 01425 #define id_quo rb_intern("quo") 01426 #define f_quo(x,y) rb_funcall((x), id_quo, 1, (y)) 01427 01428 #define f_reciprocal(x) f_quo(ONE, (x)) 01429 01430 /* 01431 The algorithm here is the method described in CLISP. Bruno Haible has 01432 graciously given permission to use this algorithm. He says, "You can use 01433 it, if you present the following explanation of the algorithm." 01434 01435 Algorithm (recursively presented): 01436 If x is a rational number, return x. 01437 If x = 0.0, return 0. 01438 If x < 0.0, return (- (rationalize (- x))). 01439 If x > 0.0: 01440 Call (integer-decode-float x). It returns a m,e,s=1 (mantissa, 01441 exponent, sign). 01442 If m = 0 or e >= 0: return x = m*2^e. 01443 Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e 01444 with smallest possible numerator and denominator. 01445 Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e. 01446 But in this case the result will be x itself anyway, regardless of 01447 the choice of a. Therefore we can simply ignore this case. 01448 Note 2: At first, we need to consider the closed interval [a,b]. 01449 but since a and b have the denominator 2^(|e|+1) whereas x itself 01450 has a denominator <= 2^|e|, we can restrict the search to the open 01451 interval (a,b). 01452 So, for given a and b (0 < a < b) we are searching a rational number 01453 y with a <= y <= b. 01454 Recursive algorithm fraction_between(a,b): 01455 c := (ceiling a) 01456 if c < b 01457 then return c ; because a <= c < b, c integer 01458 else 01459 ; a is not integer (otherwise we would have had c = a < b) 01460 k := c-1 ; k = floor(a), k < a < b <= k+1 01461 return y = k + 1/fraction_between(1/(b-k), 1/(a-k)) 01462 ; note 1 <= 1/(b-k) < 1/(a-k) 01463 01464 You can see that we are actually computing a continued fraction expansion. 01465 01466 Algorithm (iterative): 01467 If x is rational, return x. 01468 Call (integer-decode-float x). It returns a m,e,s (mantissa, 01469 exponent, sign). 01470 If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.) 01471 Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1) 01472 (positive and already in lowest terms because the denominator is a 01473 power of two and the numerator is odd). 01474 Start a continued fraction expansion 01475 p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0. 01476 Loop 01477 c := (ceiling a) 01478 if c >= b 01479 then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)), 01480 goto Loop 01481 finally partial_quotient(c). 01482 Here partial_quotient(c) denotes the iteration 01483 i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2]. 01484 At the end, return s * (p[i]/q[i]). 01485 This rational number is already in lowest terms because 01486 p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i. 01487 */ 01488 01489 static void 01490 nurat_rationalize_internal(VALUE a, VALUE b, VALUE *p, VALUE *q) 01491 { 01492 VALUE c, k, t, p0, p1, p2, q0, q1, q2; 01493 01494 p0 = ZERO; 01495 p1 = ONE; 01496 q0 = ONE; 01497 q1 = ZERO; 01498 01499 while (1) { 01500 c = f_ceil(a); 01501 if (f_lt_p(c, b)) 01502 break; 01503 k = f_sub(c, ONE); 01504 p2 = f_add(f_mul(k, p1), p0); 01505 q2 = f_add(f_mul(k, q1), q0); 01506 t = f_reciprocal(f_sub(b, k)); 01507 b = f_reciprocal(f_sub(a, k)); 01508 a = t; 01509 p0 = p1; 01510 q0 = q1; 01511 p1 = p2; 01512 q1 = q2; 01513 } 01514 *p = f_add(f_mul(c, p1), p0); 01515 *q = f_add(f_mul(c, q1), q0); 01516 } 01517 01518 /* 01519 * call-seq: 01520 * rat.rationalize -> self 01521 * rat.rationalize(eps) -> rational 01522 * 01523 * Returns a simpler approximation of the value if the optional 01524 * argument eps is given (rat-|eps| <= result <= rat+|eps|), self 01525 * otherwise. 01526 * 01527 * r = Rational(5033165, 16777216) 01528 * r.rationalize #=> (5033165/16777216) 01529 * r.rationalize(Rational('0.01')) #=> (3/10) 01530 * r.rationalize(Rational('0.1')) #=> (1/3) 01531 */ 01532 static VALUE 01533 nurat_rationalize(int argc, VALUE *argv, VALUE self) 01534 { 01535 VALUE e, a, b, p, q; 01536 01537 if (argc == 0) 01538 return self; 01539 01540 if (f_negative_p(self)) 01541 return f_negate(nurat_rationalize(argc, argv, f_abs(self))); 01542 01543 rb_scan_args(argc, argv, "01", &e); 01544 e = f_abs(e); 01545 a = f_sub(self, e); 01546 b = f_add(self, e); 01547 01548 if (f_eqeq_p(a, b)) 01549 return self; 01550 01551 nurat_rationalize_internal(a, b, &p, &q); 01552 return f_rational_new2(CLASS_OF(self), p, q); 01553 } 01554 01555 /* :nodoc: */ 01556 static VALUE 01557 nurat_hash(VALUE self) 01558 { 01559 st_index_t v, h[2]; 01560 VALUE n; 01561 01562 get_dat1(self); 01563 n = rb_hash(dat->num); 01564 h[0] = NUM2LONG(n); 01565 n = rb_hash(dat->den); 01566 h[1] = NUM2LONG(n); 01567 v = rb_memhash(h, sizeof(h)); 01568 return LONG2FIX(v); 01569 } 01570 01571 static VALUE 01572 f_format(VALUE self, VALUE (*func)(VALUE)) 01573 { 01574 VALUE s; 01575 get_dat1(self); 01576 01577 s = (*func)(dat->num); 01578 rb_str_cat2(s, "/"); 01579 rb_str_concat(s, (*func)(dat->den)); 01580 01581 return s; 01582 } 01583 01584 /* 01585 * call-seq: 01586 * rat.to_s -> string 01587 * 01588 * Returns the value as a string. 01589 * 01590 * Rational(2).to_s #=> "2/1" 01591 * Rational(-8, 6).to_s #=> "-4/3" 01592 * Rational('1/2').to_s #=> "1/2" 01593 */ 01594 static VALUE 01595 nurat_to_s(VALUE self) 01596 { 01597 return f_format(self, f_to_s); 01598 } 01599 01600 /* 01601 * call-seq: 01602 * rat.inspect -> string 01603 * 01604 * Returns the value as a string for inspection. 01605 * 01606 * Rational(2).inspect #=> "(2/1)" 01607 * Rational(-8, 6).inspect #=> "(-4/3)" 01608 * Rational('1/2').inspect #=> "(1/2)" 01609 */ 01610 static VALUE 01611 nurat_inspect(VALUE self) 01612 { 01613 VALUE s; 01614 01615 s = rb_usascii_str_new2("("); 01616 rb_str_concat(s, f_format(self, f_inspect)); 01617 rb_str_cat2(s, ")"); 01618 01619 return s; 01620 } 01621 01622 /* :nodoc: */ 01623 static VALUE 01624 nurat_dumper(VALUE self) 01625 { 01626 return self; 01627 } 01628 01629 /* :nodoc: */ 01630 static VALUE 01631 nurat_loader(VALUE self, VALUE a) 01632 { 01633 get_dat1(self); 01634 01635 dat->num = rb_ivar_get(a, id_i_num); 01636 dat->den = rb_ivar_get(a, id_i_den); 01637 01638 return self; 01639 } 01640 01641 /* :nodoc: */ 01642 static VALUE 01643 nurat_marshal_dump(VALUE self) 01644 { 01645 VALUE a; 01646 get_dat1(self); 01647 01648 a = rb_assoc_new(dat->num, dat->den); 01649 rb_copy_generic_ivar(a, self); 01650 return a; 01651 } 01652 01653 /* :nodoc: */ 01654 static VALUE 01655 nurat_marshal_load(VALUE self, VALUE a) 01656 { 01657 rb_check_frozen(self); 01658 rb_check_trusted(self); 01659 01660 Check_Type(a, T_ARRAY); 01661 if (RARRAY_LEN(a) != 2) 01662 rb_raise(rb_eArgError, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a)); 01663 if (f_zero_p(RARRAY_PTR(a)[1])) 01664 rb_raise_zerodiv(); 01665 01666 rb_ivar_set(self, id_i_num, RARRAY_PTR(a)[0]); 01667 rb_ivar_set(self, id_i_den, RARRAY_PTR(a)[1]); 01668 01669 return self; 01670 } 01671 01672 /* --- */ 01673 01674 VALUE 01675 rb_rational_reciprocal(VALUE x) 01676 { 01677 get_dat1(x); 01678 return f_rational_new_no_reduce2(CLASS_OF(x), dat->den, dat->num); 01679 } 01680 01681 /* 01682 * call-seq: 01683 * int.gcd(int2) -> integer 01684 * 01685 * Returns the greatest common divisor (always positive). 0.gcd(x) 01686 * and x.gcd(0) return abs(x). 01687 * 01688 * 2.gcd(2) #=> 2 01689 * 3.gcd(-7) #=> 1 01690 * ((1<<31)-1).gcd((1<<61)-1) #=> 1 01691 */ 01692 VALUE 01693 rb_gcd(VALUE self, VALUE other) 01694 { 01695 other = nurat_int_value(other); 01696 return f_gcd(self, other); 01697 } 01698 01699 /* 01700 * call-seq: 01701 * int.lcm(int2) -> integer 01702 * 01703 * Returns the least common multiple (always positive). 0.lcm(x) and 01704 * x.lcm(0) return zero. 01705 * 01706 * 2.lcm(2) #=> 2 01707 * 3.lcm(-7) #=> 21 01708 * ((1<<31)-1).lcm((1<<61)-1) #=> 4951760154835678088235319297 01709 */ 01710 VALUE 01711 rb_lcm(VALUE self, VALUE other) 01712 { 01713 other = nurat_int_value(other); 01714 return f_lcm(self, other); 01715 } 01716 01717 /* 01718 * call-seq: 01719 * int.gcdlcm(int2) -> array 01720 * 01721 * Returns an array; [int.gcd(int2), int.lcm(int2)]. 01722 * 01723 * 2.gcdlcm(2) #=> [2, 2] 01724 * 3.gcdlcm(-7) #=> [1, 21] 01725 * ((1<<31)-1).gcdlcm((1<<61)-1) #=> [1, 4951760154835678088235319297] 01726 */ 01727 VALUE 01728 rb_gcdlcm(VALUE self, VALUE other) 01729 { 01730 other = nurat_int_value(other); 01731 return rb_assoc_new(f_gcd(self, other), f_lcm(self, other)); 01732 } 01733 01734 VALUE 01735 rb_rational_raw(VALUE x, VALUE y) 01736 { 01737 return nurat_s_new_internal(rb_cRational, x, y); 01738 } 01739 01740 VALUE 01741 rb_rational_new(VALUE x, VALUE y) 01742 { 01743 return nurat_s_canonicalize_internal(rb_cRational, x, y); 01744 } 01745 01746 static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass); 01747 01748 VALUE 01749 rb_Rational(VALUE x, VALUE y) 01750 { 01751 VALUE a[2]; 01752 a[0] = x; 01753 a[1] = y; 01754 return nurat_s_convert(2, a, rb_cRational); 01755 } 01756 01757 #define id_numerator rb_intern("numerator") 01758 #define f_numerator(x) rb_funcall((x), id_numerator, 0) 01759 01760 #define id_denominator rb_intern("denominator") 01761 #define f_denominator(x) rb_funcall((x), id_denominator, 0) 01762 01763 #define id_to_r rb_intern("to_r") 01764 #define f_to_r(x) rb_funcall((x), id_to_r, 0) 01765 01766 /* 01767 * call-seq: 01768 * num.numerator -> integer 01769 * 01770 * Returns the numerator. 01771 */ 01772 static VALUE 01773 numeric_numerator(VALUE self) 01774 { 01775 return f_numerator(f_to_r(self)); 01776 } 01777 01778 /* 01779 * call-seq: 01780 * num.denominator -> integer 01781 * 01782 * Returns the denominator (always positive). 01783 */ 01784 static VALUE 01785 numeric_denominator(VALUE self) 01786 { 01787 return f_denominator(f_to_r(self)); 01788 } 01789 01790 /* 01791 * call-seq: 01792 * int.numerator -> self 01793 * 01794 * Returns self. 01795 */ 01796 static VALUE 01797 integer_numerator(VALUE self) 01798 { 01799 return self; 01800 } 01801 01802 /* 01803 * call-seq: 01804 * int.denominator -> 1 01805 * 01806 * Returns 1. 01807 */ 01808 static VALUE 01809 integer_denominator(VALUE self) 01810 { 01811 return INT2FIX(1); 01812 } 01813 01814 /* 01815 * call-seq: 01816 * flo.numerator -> integer 01817 * 01818 * Returns the numerator. The result is machine dependent. 01819 * 01820 * n = 0.3.numerator #=> 5404319552844595 01821 * d = 0.3.denominator #=> 18014398509481984 01822 * n.fdiv(d) #=> 0.3 01823 */ 01824 static VALUE 01825 float_numerator(VALUE self) 01826 { 01827 double d = RFLOAT_VALUE(self); 01828 if (isinf(d) || isnan(d)) 01829 return self; 01830 return rb_call_super(0, 0); 01831 } 01832 01833 /* 01834 * call-seq: 01835 * flo.denominator -> integer 01836 * 01837 * Returns the denominator (always positive). The result is machine 01838 * dependent. 01839 * 01840 * See numerator. 01841 */ 01842 static VALUE 01843 float_denominator(VALUE self) 01844 { 01845 double d = RFLOAT_VALUE(self); 01846 if (isinf(d) || isnan(d)) 01847 return INT2FIX(1); 01848 return rb_call_super(0, 0); 01849 } 01850 01851 /* 01852 * call-seq: 01853 * nil.to_r -> (0/1) 01854 * 01855 * Returns zero as a rational. 01856 */ 01857 static VALUE 01858 nilclass_to_r(VALUE self) 01859 { 01860 return rb_rational_new1(INT2FIX(0)); 01861 } 01862 01863 /* 01864 * call-seq: 01865 * nil.rationalize([eps]) -> (0/1) 01866 * 01867 * Returns zero as a rational. The optional argument eps is always 01868 * ignored. 01869 */ 01870 static VALUE 01871 nilclass_rationalize(int argc, VALUE *argv, VALUE self) 01872 { 01873 rb_scan_args(argc, argv, "01", NULL); 01874 return nilclass_to_r(self); 01875 } 01876 01877 /* 01878 * call-seq: 01879 * int.to_r -> rational 01880 * 01881 * Returns the value as a rational. 01882 * 01883 * 1.to_r #=> (1/1) 01884 * (1<<64).to_r #=> (18446744073709551616/1) 01885 */ 01886 static VALUE 01887 integer_to_r(VALUE self) 01888 { 01889 return rb_rational_new1(self); 01890 } 01891 01892 /* 01893 * call-seq: 01894 * int.rationalize([eps]) -> rational 01895 * 01896 * Returns the value as a rational. The optional argument eps is 01897 * always ignored. 01898 */ 01899 static VALUE 01900 integer_rationalize(int argc, VALUE *argv, VALUE self) 01901 { 01902 rb_scan_args(argc, argv, "01", NULL); 01903 return integer_to_r(self); 01904 } 01905 01906 static void 01907 float_decode_internal(VALUE self, VALUE *rf, VALUE *rn) 01908 { 01909 double f; 01910 int n; 01911 01912 f = frexp(RFLOAT_VALUE(self), &n); 01913 f = ldexp(f, DBL_MANT_DIG); 01914 n -= DBL_MANT_DIG; 01915 *rf = rb_dbl2big(f); 01916 *rn = INT2FIX(n); 01917 } 01918 01919 #if 0 01920 static VALUE 01921 float_decode(VALUE self) 01922 { 01923 VALUE f, n; 01924 01925 float_decode_internal(self, &f, &n); 01926 return rb_assoc_new(f, n); 01927 } 01928 #endif 01929 01930 #define id_lshift rb_intern("<<") 01931 #define f_lshift(x,n) rb_funcall((x), id_lshift, 1, (n)) 01932 01933 /* 01934 * call-seq: 01935 * flt.to_r -> rational 01936 * 01937 * Returns the value as a rational. 01938 * 01939 * NOTE: 0.3.to_r isn't the same as '0.3'.to_r. The latter is 01940 * equivalent to '3/10'.to_r, but the former isn't so. 01941 * 01942 * 2.0.to_r #=> (2/1) 01943 * 2.5.to_r #=> (5/2) 01944 * -0.75.to_r #=> (-3/4) 01945 * 0.0.to_r #=> (0/1) 01946 * 01947 * See rationalize. 01948 */ 01949 static VALUE 01950 float_to_r(VALUE self) 01951 { 01952 VALUE f, n; 01953 01954 float_decode_internal(self, &f, &n); 01955 #if FLT_RADIX == 2 01956 { 01957 long ln = FIX2LONG(n); 01958 01959 if (ln == 0) 01960 return f_to_r(f); 01961 if (ln > 0) 01962 return f_to_r(f_lshift(f, n)); 01963 ln = -ln; 01964 return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln))); 01965 } 01966 #else 01967 return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n))); 01968 #endif 01969 } 01970 01971 /* 01972 * call-seq: 01973 * flt.rationalize([eps]) -> rational 01974 * 01975 * Returns a simpler approximation of the value (flt-|eps| <= result 01976 * <= flt+|eps|). if the optional eps is not given, it will be chosen 01977 * automatically. 01978 * 01979 * 0.3.rationalize #=> (3/10) 01980 * 1.333.rationalize #=> (1333/1000) 01981 * 1.333.rationalize(0.01) #=> (4/3) 01982 * 01983 * See to_r. 01984 */ 01985 static VALUE 01986 float_rationalize(int argc, VALUE *argv, VALUE self) 01987 { 01988 VALUE e, a, b, p, q; 01989 01990 if (f_negative_p(self)) 01991 return f_negate(float_rationalize(argc, argv, f_abs(self))); 01992 01993 rb_scan_args(argc, argv, "01", &e); 01994 01995 if (argc != 0) { 01996 e = f_abs(e); 01997 a = f_sub(self, e); 01998 b = f_add(self, e); 01999 } 02000 else { 02001 VALUE f, n; 02002 02003 float_decode_internal(self, &f, &n); 02004 if (f_zero_p(f) || f_positive_p(n)) 02005 return rb_rational_new1(f_lshift(f, n)); 02006 02007 #if FLT_RADIX == 2 02008 { 02009 VALUE two_times_f, den; 02010 02011 two_times_f = f_mul(TWO, f); 02012 den = f_lshift(ONE, f_sub(ONE, n)); 02013 02014 a = rb_rational_new2(f_sub(two_times_f, ONE), den); 02015 b = rb_rational_new2(f_add(two_times_f, ONE), den); 02016 } 02017 #else 02018 { 02019 VALUE radix_times_f, den; 02020 02021 radix_times_f = f_mul(INT2FIX(FLT_RADIX), f); 02022 den = f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n)); 02023 02024 a = rb_rational_new2(f_sub(radix_times_f, INT2FIX(FLT_RADIX - 1)), den); 02025 b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den); 02026 } 02027 #endif 02028 } 02029 02030 if (f_eqeq_p(a, b)) 02031 return f_to_r(self); 02032 02033 nurat_rationalize_internal(a, b, &p, &q); 02034 return rb_rational_new2(p, q); 02035 } 02036 02037 #include <ctype.h> 02038 02039 inline static int 02040 issign(int c) 02041 { 02042 return (c == '-' || c == '+'); 02043 } 02044 02045 static int 02046 read_sign(const char **s) 02047 { 02048 int sign = '?'; 02049 02050 if (issign(**s)) { 02051 sign = **s; 02052 (*s)++; 02053 } 02054 return sign; 02055 } 02056 02057 inline static int 02058 isdecimal(int c) 02059 { 02060 return isdigit((unsigned char)c); 02061 } 02062 02063 static int 02064 read_digits(const char **s, int strict, 02065 VALUE *num, int *count) 02066 { 02067 char *b, *bb; 02068 int us = 1, ret = 1; 02069 02070 if (!isdecimal(**s)) { 02071 *num = ZERO; 02072 return 0; 02073 } 02074 02075 bb = b = ALLOCA_N(char, strlen(*s) + 1); 02076 02077 while (isdecimal(**s) || **s == '_') { 02078 if (**s == '_') { 02079 if (strict) { 02080 if (us) { 02081 ret = 0; 02082 goto conv; 02083 } 02084 } 02085 us = 1; 02086 } 02087 else { 02088 if (count) 02089 (*count)++; 02090 *b++ = **s; 02091 us = 0; 02092 } 02093 (*s)++; 02094 } 02095 if (us) 02096 do { 02097 (*s)--; 02098 } while (**s == '_'); 02099 conv: 02100 *b = '\0'; 02101 *num = rb_cstr_to_inum(bb, 10, 0); 02102 return ret; 02103 } 02104 02105 inline static int 02106 islettere(int c) 02107 { 02108 return (c == 'e' || c == 'E'); 02109 } 02110 02111 static int 02112 read_num(const char **s, int numsign, int strict, 02113 VALUE *num) 02114 { 02115 VALUE ip, fp, exp; 02116 02117 *num = rb_rational_new2(ZERO, ONE); 02118 exp = Qnil; 02119 02120 if (**s != '.') { 02121 if (!read_digits(s, strict, &ip, NULL)) 02122 return 0; 02123 *num = rb_rational_new2(ip, ONE); 02124 } 02125 02126 if (**s == '.') { 02127 int count = 0; 02128 02129 (*s)++; 02130 if (!read_digits(s, strict, &fp, &count)) 02131 return 0; 02132 { 02133 VALUE l = f_expt10(INT2NUM(count)); 02134 *num = f_mul(*num, l); 02135 *num = f_add(*num, fp); 02136 *num = f_div(*num, l); 02137 } 02138 } 02139 02140 if (islettere(**s)) { 02141 int expsign; 02142 02143 (*s)++; 02144 expsign = read_sign(s); 02145 if (!read_digits(s, strict, &exp, NULL)) 02146 return 0; 02147 if (expsign == '-') 02148 exp = f_negate(exp); 02149 } 02150 02151 if (numsign == '-') 02152 *num = f_negate(*num); 02153 if (!NIL_P(exp)) { 02154 VALUE l = f_expt10(exp); 02155 *num = f_mul(*num, l); 02156 } 02157 return 1; 02158 } 02159 02160 inline static int 02161 read_den(const char **s, int strict, 02162 VALUE *num) 02163 { 02164 if (!read_digits(s, strict, num, NULL)) 02165 return 0; 02166 return 1; 02167 } 02168 02169 static int 02170 read_rat_nos(const char **s, int sign, int strict, 02171 VALUE *num) 02172 { 02173 VALUE den; 02174 02175 if (!read_num(s, sign, strict, num)) 02176 return 0; 02177 if (**s == '/') { 02178 (*s)++; 02179 if (!read_den(s, strict, &den)) 02180 return 0; 02181 if (!(FIXNUM_P(den) && FIX2LONG(den) == 1)) 02182 *num = f_div(*num, den); 02183 } 02184 return 1; 02185 } 02186 02187 static int 02188 read_rat(const char **s, int strict, 02189 VALUE *num) 02190 { 02191 int sign; 02192 02193 sign = read_sign(s); 02194 if (!read_rat_nos(s, sign, strict, num)) 02195 return 0; 02196 return 1; 02197 } 02198 02199 inline static void 02200 skip_ws(const char **s) 02201 { 02202 while (isspace((unsigned char)**s)) 02203 (*s)++; 02204 } 02205 02206 static int 02207 parse_rat(const char *s, int strict, 02208 VALUE *num) 02209 { 02210 skip_ws(&s); 02211 if (!read_rat(&s, strict, num)) 02212 return 0; 02213 skip_ws(&s); 02214 02215 if (strict) 02216 if (*s != '\0') 02217 return 0; 02218 return 1; 02219 } 02220 02221 static VALUE 02222 string_to_r_strict(VALUE self) 02223 { 02224 char *s; 02225 VALUE num; 02226 02227 rb_must_asciicompat(self); 02228 02229 s = RSTRING_PTR(self); 02230 02231 if (!s || memchr(s, '\0', RSTRING_LEN(self))) 02232 rb_raise(rb_eArgError, "string contains null byte"); 02233 02234 if (s && s[RSTRING_LEN(self)]) { 02235 rb_str_modify(self); 02236 s = RSTRING_PTR(self); 02237 s[RSTRING_LEN(self)] = '\0'; 02238 } 02239 02240 if (!s) 02241 s = (char *)""; 02242 02243 if (!parse_rat(s, 1, &num)) { 02244 VALUE ins = f_inspect(self); 02245 rb_raise(rb_eArgError, "invalid value for convert(): %s", 02246 StringValuePtr(ins)); 02247 } 02248 02249 if (RB_TYPE_P(num, T_FLOAT)) 02250 rb_raise(rb_eFloatDomainError, "Infinity"); 02251 return num; 02252 } 02253 02254 /* 02255 * call-seq: 02256 * str.to_r -> rational 02257 * 02258 * Returns a rational which denotes the string form. The parser 02259 * ignores leading whitespaces and trailing garbage. Any digit 02260 * sequences can be separated by an underscore. Returns zero for null 02261 * or garbage string. 02262 * 02263 * NOTE: '0.3'.to_r isn't the same as 0.3.to_r. The former is 02264 * equivalent to '3/10'.to_r, but the latter isn't so. 02265 * 02266 * ' 2 '.to_r #=> (2/1) 02267 * '300/2'.to_r #=> (150/1) 02268 * '-9.2'.to_r #=> (-46/5) 02269 * '-9.2e2'.to_r #=> (-920/1) 02270 * '1_234_567'.to_r #=> (1234567/1) 02271 * '21 june 09'.to_r #=> (21/1) 02272 * '21/06/09'.to_r #=> (7/2) 02273 * 'bwv 1079'.to_r #=> (0/1) 02274 * 02275 * See Kernel.Rational. 02276 */ 02277 static VALUE 02278 string_to_r(VALUE self) 02279 { 02280 char *s; 02281 VALUE num; 02282 02283 rb_must_asciicompat(self); 02284 02285 s = RSTRING_PTR(self); 02286 02287 if (s && s[RSTRING_LEN(self)]) { 02288 rb_str_modify(self); 02289 s = RSTRING_PTR(self); 02290 s[RSTRING_LEN(self)] = '\0'; 02291 } 02292 02293 if (!s) 02294 s = (char *)""; 02295 02296 (void)parse_rat(s, 0, &num); 02297 02298 if (RB_TYPE_P(num, T_FLOAT)) 02299 rb_raise(rb_eFloatDomainError, "Infinity"); 02300 return num; 02301 } 02302 02303 VALUE 02304 rb_cstr_to_rat(const char *s, int strict) /* for complex's internal */ 02305 { 02306 VALUE num; 02307 02308 (void)parse_rat(s, strict, &num); 02309 02310 if (RB_TYPE_P(num, T_FLOAT)) 02311 rb_raise(rb_eFloatDomainError, "Infinity"); 02312 return num; 02313 } 02314 02315 static VALUE 02316 nurat_s_convert(int argc, VALUE *argv, VALUE klass) 02317 { 02318 VALUE a1, a2, backref; 02319 02320 rb_scan_args(argc, argv, "11", &a1, &a2); 02321 02322 if (NIL_P(a1) || (argc == 2 && NIL_P(a2))) 02323 rb_raise(rb_eTypeError, "can't convert nil into Rational"); 02324 02325 switch (TYPE(a1)) { 02326 case T_COMPLEX: 02327 if (k_exact_zero_p(RCOMPLEX(a1)->imag)) 02328 a1 = RCOMPLEX(a1)->real; 02329 } 02330 02331 switch (TYPE(a2)) { 02332 case T_COMPLEX: 02333 if (k_exact_zero_p(RCOMPLEX(a2)->imag)) 02334 a2 = RCOMPLEX(a2)->real; 02335 } 02336 02337 backref = rb_backref_get(); 02338 rb_match_busy(backref); 02339 02340 switch (TYPE(a1)) { 02341 case T_FIXNUM: 02342 case T_BIGNUM: 02343 break; 02344 case T_FLOAT: 02345 a1 = f_to_r(a1); 02346 break; 02347 case T_STRING: 02348 a1 = string_to_r_strict(a1); 02349 break; 02350 } 02351 02352 switch (TYPE(a2)) { 02353 case T_FIXNUM: 02354 case T_BIGNUM: 02355 break; 02356 case T_FLOAT: 02357 a2 = f_to_r(a2); 02358 break; 02359 case T_STRING: 02360 a2 = string_to_r_strict(a2); 02361 break; 02362 } 02363 02364 rb_backref_set(backref); 02365 02366 switch (TYPE(a1)) { 02367 case T_RATIONAL: 02368 if (argc == 1 || (k_exact_one_p(a2))) 02369 return a1; 02370 } 02371 02372 if (argc == 1) { 02373 if (!(k_numeric_p(a1) && k_integer_p(a1))) 02374 return rb_convert_type(a1, T_RATIONAL, "Rational", "to_r"); 02375 } 02376 else { 02377 if ((k_numeric_p(a1) && k_numeric_p(a2)) && 02378 (!f_integer_p(a1) || !f_integer_p(a2))) 02379 return f_div(a1, a2); 02380 } 02381 02382 { 02383 VALUE argv2[2]; 02384 argv2[0] = a1; 02385 argv2[1] = a2; 02386 return nurat_s_new(argc, argv2, klass); 02387 } 02388 } 02389 02390 /* 02391 * A rational number can be represented as a paired integer number; 02392 * a/b (b>0). Where a is numerator and b is denominator. Integer a 02393 * equals rational a/1 mathematically. 02394 * 02395 * In ruby, you can create rational object with Rational, to_r or 02396 * rationalize method. The return values will be irreducible. 02397 * 02398 * Rational(1) #=> (1/1) 02399 * Rational(2, 3) #=> (2/3) 02400 * Rational(4, -6) #=> (-2/3) 02401 * 3.to_r #=> (3/1) 02402 * 02403 * You can also create rational object from floating-point numbers or 02404 * strings. 02405 * 02406 * Rational(0.3) #=> (5404319552844595/18014398509481984) 02407 * Rational('0.3') #=> (3/10) 02408 * Rational('2/3') #=> (2/3) 02409 * 02410 * 0.3.to_r #=> (5404319552844595/18014398509481984) 02411 * '0.3'.to_r #=> (3/10) 02412 * '2/3'.to_r #=> (2/3) 02413 * 0.3.rationalize #=> (3/10) 02414 * 02415 * A rational object is an exact number, which helps you to write 02416 * program without any rounding errors. 02417 * 02418 * 10.times.inject(0){|t,| t + 0.1} #=> 0.9999999999999999 02419 * 10.times.inject(0){|t,| t + Rational('0.1')} #=> (1/1) 02420 * 02421 * However, when an expression has inexact factor (numerical value or 02422 * operation), will produce an inexact result. 02423 * 02424 * Rational(10) / 3 #=> (10/3) 02425 * Rational(10) / 3.0 #=> 3.3333333333333335 02426 * 02427 * Rational(-8) ** Rational(1, 3) 02428 * #=> (1.0000000000000002+1.7320508075688772i) 02429 */ 02430 void 02431 Init_Rational(void) 02432 { 02433 VALUE compat; 02434 #undef rb_intern 02435 #define rb_intern(str) rb_intern_const(str) 02436 02437 assert(fprintf(stderr, "assert() is now active\n")); 02438 02439 id_abs = rb_intern("abs"); 02440 id_cmp = rb_intern("<=>"); 02441 id_convert = rb_intern("convert"); 02442 id_eqeq_p = rb_intern("=="); 02443 id_expt = rb_intern("**"); 02444 id_fdiv = rb_intern("fdiv"); 02445 id_floor = rb_intern("floor"); 02446 id_idiv = rb_intern("div"); 02447 id_inspect = rb_intern("inspect"); 02448 id_integer_p = rb_intern("integer?"); 02449 id_negate = rb_intern("-@"); 02450 id_to_f = rb_intern("to_f"); 02451 id_to_i = rb_intern("to_i"); 02452 id_to_s = rb_intern("to_s"); 02453 id_truncate = rb_intern("truncate"); 02454 id_i_num = rb_intern("@numerator"); 02455 id_i_den = rb_intern("@denominator"); 02456 02457 rb_cRational = rb_define_class("Rational", rb_cNumeric); 02458 02459 rb_define_alloc_func(rb_cRational, nurat_s_alloc); 02460 rb_undef_method(CLASS_OF(rb_cRational), "allocate"); 02461 02462 #if 0 02463 rb_define_private_method(CLASS_OF(rb_cRational), "new!", nurat_s_new_bang, -1); 02464 rb_define_private_method(CLASS_OF(rb_cRational), "new", nurat_s_new, -1); 02465 #else 02466 rb_undef_method(CLASS_OF(rb_cRational), "new"); 02467 #endif 02468 02469 rb_define_global_function("Rational", nurat_f_rational, -1); 02470 02471 rb_define_method(rb_cRational, "numerator", nurat_numerator, 0); 02472 rb_define_method(rb_cRational, "denominator", nurat_denominator, 0); 02473 02474 rb_define_method(rb_cRational, "+", nurat_add, 1); 02475 rb_define_method(rb_cRational, "-", nurat_sub, 1); 02476 rb_define_method(rb_cRational, "*", nurat_mul, 1); 02477 rb_define_method(rb_cRational, "/", nurat_div, 1); 02478 rb_define_method(rb_cRational, "quo", nurat_div, 1); 02479 rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1); 02480 rb_define_method(rb_cRational, "**", nurat_expt, 1); 02481 02482 rb_define_method(rb_cRational, "<=>", nurat_cmp, 1); 02483 rb_define_method(rb_cRational, "==", nurat_eqeq_p, 1); 02484 rb_define_method(rb_cRational, "coerce", nurat_coerce, 1); 02485 02486 #if 0 /* NUBY */ 02487 rb_define_method(rb_cRational, "//", nurat_idiv, 1); 02488 #endif 02489 02490 #if 0 02491 rb_define_method(rb_cRational, "quot", nurat_quot, 1); 02492 rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1); 02493 #endif 02494 02495 #if 0 02496 rb_define_method(rb_cRational, "rational?", nurat_true, 0); 02497 rb_define_method(rb_cRational, "exact?", nurat_true, 0); 02498 #endif 02499 02500 rb_define_method(rb_cRational, "floor", nurat_floor_n, -1); 02501 rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1); 02502 rb_define_method(rb_cRational, "truncate", nurat_truncate_n, -1); 02503 rb_define_method(rb_cRational, "round", nurat_round_n, -1); 02504 02505 rb_define_method(rb_cRational, "to_i", nurat_truncate, 0); 02506 rb_define_method(rb_cRational, "to_f", nurat_to_f, 0); 02507 rb_define_method(rb_cRational, "to_r", nurat_to_r, 0); 02508 rb_define_method(rb_cRational, "rationalize", nurat_rationalize, -1); 02509 02510 rb_define_method(rb_cRational, "hash", nurat_hash, 0); 02511 02512 rb_define_method(rb_cRational, "to_s", nurat_to_s, 0); 02513 rb_define_method(rb_cRational, "inspect", nurat_inspect, 0); 02514 02515 rb_define_private_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0); 02516 compat = rb_define_class_under(rb_cRational, "compatible", rb_cObject); 02517 rb_define_private_method(compat, "marshal_load", nurat_marshal_load, 1); 02518 rb_marshal_define_compat(rb_cRational, compat, nurat_dumper, nurat_loader); 02519 02520 /* --- */ 02521 02522 rb_define_method(rb_cInteger, "gcd", rb_gcd, 1); 02523 rb_define_method(rb_cInteger, "lcm", rb_lcm, 1); 02524 rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1); 02525 02526 rb_define_method(rb_cNumeric, "numerator", numeric_numerator, 0); 02527 rb_define_method(rb_cNumeric, "denominator", numeric_denominator, 0); 02528 02529 rb_define_method(rb_cInteger, "numerator", integer_numerator, 0); 02530 rb_define_method(rb_cInteger, "denominator", integer_denominator, 0); 02531 02532 rb_define_method(rb_cFloat, "numerator", float_numerator, 0); 02533 rb_define_method(rb_cFloat, "denominator", float_denominator, 0); 02534 02535 rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0); 02536 rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1); 02537 rb_define_method(rb_cInteger, "to_r", integer_to_r, 0); 02538 rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1); 02539 rb_define_method(rb_cFloat, "to_r", float_to_r, 0); 02540 rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1); 02541 02542 rb_define_method(rb_cString, "to_r", string_to_r, 0); 02543 02544 rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1); 02545 } 02546 02547 /* 02548 Local variables: 02549 c-file-style: "ruby" 02550 End: 02551 */ 02552