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