1 /*
2 rational.c: Coded by Tadayoshi Funaba 2008-2012
3
4 This implementation is based on Keiju Ishitsuka's Rational library
5 which is written in ruby.
6 */
7
8 #include "internal.h"
9 #include "id.h"
10 #include <math.h>
11 #include <float.h>
12
13 #ifdef HAVE_IEEEFP_H
14 #include <ieeefp.h>
15 #endif
16
17 #define NDEBUG
18 #include "ruby_assert.h"
19
20 #if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
21 #define USE_GMP
22 #include <gmp.h>
23 #endif
24
25 #define ZERO INT2FIX(0)
26 #define ONE INT2FIX(1)
27 #define TWO INT2FIX(2)
28
29 #define GMP_GCD_DIGITS 1
30
31 #define INT_POSITIVE_P(x) (FIXNUM_P(x) ? FIXNUM_POSITIVE_P(x) : BIGNUM_POSITIVE_P(x))
32 #define INT_ZERO_P(x) (FIXNUM_P(x) ? FIXNUM_ZERO_P(x) : rb_bigzero_p(x))
33
34 VALUE rb_cRational;
35
36 static ID id_abs, id_idiv, id_integer_p,
37 id_i_num, id_i_den;
38 #define id_to_i idTo_i
39
40 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
41 #define f_inspect rb_inspect
42 #define f_to_s rb_obj_as_string
43
44 static VALUE nurat_to_f(VALUE self);
45
46 #define binop(n,op) \
47 inline static VALUE \
48 f_##n(VALUE x, VALUE y)\
49 {\
50 return rb_funcall(x, (op), 1, y); \
51 }
52
53 #define fun1(n) \
54 inline static VALUE \
55 f_##n(VALUE x)\
56 {\
57 return rb_funcall(x, id_##n, 0);\
58 }
59
60 inline static VALUE
f_add(VALUE x,VALUE y)61 f_add(VALUE x, VALUE y)
62 {
63 if (FIXNUM_ZERO_P(y))
64 return x;
65 if (FIXNUM_ZERO_P(x))
66 return y;
67 return rb_funcall(x, '+', 1, y);
68 }
69
70 inline static VALUE
f_div(VALUE x,VALUE y)71 f_div(VALUE x, VALUE y)
72 {
73 if (y == ONE)
74 return x;
75 if (RB_INTEGER_TYPE_P(x))
76 return rb_int_div(x, y);
77 return rb_funcall(x, '/', 1, y);
78 }
79
80 inline static int
f_lt_p(VALUE x,VALUE y)81 f_lt_p(VALUE x, VALUE y)
82 {
83 if (FIXNUM_P(x) && FIXNUM_P(y))
84 return (SIGNED_VALUE)x < (SIGNED_VALUE)y;
85 return RTEST(rb_funcall(x, '<', 1, y));
86 }
87
88 #ifndef NDEBUG
89 /* f_mod is used only in f_gcd defined when NDEBUG is not defined */
90 binop(mod, '%')
91 #endif
92
93 inline static VALUE
f_mul(VALUE x,VALUE y)94 f_mul(VALUE x, VALUE y)
95 {
96 if (FIXNUM_ZERO_P(y) && RB_INTEGER_TYPE_P(x))
97 return ZERO;
98 if (y == ONE) return x;
99 if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y))
100 return ZERO;
101 if (x == ONE) return y;
102 else if (RB_INTEGER_TYPE_P(x))
103 return rb_int_mul(x, y);
104 return rb_funcall(x, '*', 1, y);
105 }
106
107 inline static VALUE
f_sub(VALUE x,VALUE y)108 f_sub(VALUE x, VALUE y)
109 {
110 if (FIXNUM_P(y) && FIXNUM_ZERO_P(y))
111 return x;
112 return rb_funcall(x, '-', 1, y);
113 }
114
115 inline static VALUE
f_abs(VALUE x)116 f_abs(VALUE x)
117 {
118 if (RB_INTEGER_TYPE_P(x))
119 return rb_int_abs(x);
120 return rb_funcall(x, id_abs, 0);
121 }
122
fun1(integer_p)123 fun1(integer_p)
124
125 inline static VALUE
126 f_to_i(VALUE x)
127 {
128 if (RB_TYPE_P(x, T_STRING))
129 return rb_str_to_inum(x, 10, 0);
130 return rb_funcall(x, id_to_i, 0);
131 }
132
133 inline static VALUE
f_eqeq_p(VALUE x,VALUE y)134 f_eqeq_p(VALUE x, VALUE y)
135 {
136 if (FIXNUM_P(x) && FIXNUM_P(y))
137 return x == y;
138 return (int)rb_equal(x, y);
139 }
140
141 inline static VALUE
f_idiv(VALUE x,VALUE y)142 f_idiv(VALUE x, VALUE y)
143 {
144 if (RB_INTEGER_TYPE_P(x))
145 return rb_int_idiv(x, y);
146 return rb_funcall(x, id_idiv, 1, y);
147 }
148
149 #define f_expt10(x) rb_int_pow(INT2FIX(10), x)
150
151 inline static int
f_zero_p(VALUE x)152 f_zero_p(VALUE x)
153 {
154 if (RB_INTEGER_TYPE_P(x)) {
155 return FIXNUM_ZERO_P(x);
156 }
157 else if (RB_TYPE_P(x, T_RATIONAL)) {
158 VALUE num = RRATIONAL(x)->num;
159
160 return FIXNUM_ZERO_P(num);
161 }
162 return (int)rb_equal(x, ZERO);
163 }
164
165 #define f_nonzero_p(x) (!f_zero_p(x))
166
167 inline static int
f_one_p(VALUE x)168 f_one_p(VALUE x)
169 {
170 if (RB_INTEGER_TYPE_P(x)) {
171 return x == LONG2FIX(1);
172 }
173 else if (RB_TYPE_P(x, T_RATIONAL)) {
174 VALUE num = RRATIONAL(x)->num;
175 VALUE den = RRATIONAL(x)->den;
176
177 return num == LONG2FIX(1) && den == LONG2FIX(1);
178 }
179 return (int)rb_equal(x, ONE);
180 }
181
182 inline static int
f_minus_one_p(VALUE x)183 f_minus_one_p(VALUE x)
184 {
185 if (RB_INTEGER_TYPE_P(x)) {
186 return x == LONG2FIX(-1);
187 }
188 else if (RB_TYPE_P(x, T_BIGNUM)) {
189 return Qfalse;
190 }
191 else if (RB_TYPE_P(x, T_RATIONAL)) {
192 VALUE num = RRATIONAL(x)->num;
193 VALUE den = RRATIONAL(x)->den;
194
195 return num == LONG2FIX(-1) && den == LONG2FIX(1);
196 }
197 return (int)rb_equal(x, INT2FIX(-1));
198 }
199
200 inline static int
f_kind_of_p(VALUE x,VALUE c)201 f_kind_of_p(VALUE x, VALUE c)
202 {
203 return (int)rb_obj_is_kind_of(x, c);
204 }
205
206 inline static int
k_numeric_p(VALUE x)207 k_numeric_p(VALUE x)
208 {
209 return f_kind_of_p(x, rb_cNumeric);
210 }
211
212 inline static int
k_integer_p(VALUE x)213 k_integer_p(VALUE x)
214 {
215 return RB_INTEGER_TYPE_P(x);
216 }
217
218 inline static int
k_float_p(VALUE x)219 k_float_p(VALUE x)
220 {
221 return RB_FLOAT_TYPE_P(x);
222 }
223
224 inline static int
k_rational_p(VALUE x)225 k_rational_p(VALUE x)
226 {
227 return RB_TYPE_P(x, T_RATIONAL);
228 }
229
230 #define k_exact_p(x) (!k_float_p(x))
231 #define k_inexact_p(x) k_float_p(x)
232
233 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
234 #define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
235
236 #ifdef USE_GMP
237 VALUE
rb_gcd_gmp(VALUE x,VALUE y)238 rb_gcd_gmp(VALUE x, VALUE y)
239 {
240 const size_t nails = (sizeof(BDIGIT)-SIZEOF_BDIGIT)*CHAR_BIT;
241 mpz_t mx, my, mz;
242 size_t count;
243 VALUE z;
244 long zn;
245
246 mpz_init(mx);
247 mpz_init(my);
248 mpz_init(mz);
249 mpz_import(mx, BIGNUM_LEN(x), -1, sizeof(BDIGIT), 0, nails, BIGNUM_DIGITS(x));
250 mpz_import(my, BIGNUM_LEN(y), -1, sizeof(BDIGIT), 0, nails, BIGNUM_DIGITS(y));
251
252 mpz_gcd(mz, mx, my);
253
254 mpz_clear(mx);
255 mpz_clear(my);
256
257 zn = (mpz_sizeinbase(mz, 16) + SIZEOF_BDIGIT*2 - 1) / (SIZEOF_BDIGIT*2);
258 z = rb_big_new(zn, 1);
259 mpz_export(BIGNUM_DIGITS(z), &count, -1, sizeof(BDIGIT), 0, nails, mz);
260
261 mpz_clear(mz);
262
263 return rb_big_norm(z);
264 }
265 #endif
266
267 #ifndef NDEBUG
268 #define f_gcd f_gcd_orig
269 #endif
270
271 inline static long
i_gcd(long x,long y)272 i_gcd(long x, long y)
273 {
274 unsigned long u, v, t;
275 int shift;
276
277 if (x < 0)
278 x = -x;
279 if (y < 0)
280 y = -y;
281
282 if (x == 0)
283 return y;
284 if (y == 0)
285 return x;
286
287 u = (unsigned long)x;
288 v = (unsigned long)y;
289 for (shift = 0; ((u | v) & 1) == 0; ++shift) {
290 u >>= 1;
291 v >>= 1;
292 }
293
294 while ((u & 1) == 0)
295 u >>= 1;
296
297 do {
298 while ((v & 1) == 0)
299 v >>= 1;
300
301 if (u > v) {
302 t = v;
303 v = u;
304 u = t;
305 }
306 v = v - u;
307 } while (v != 0);
308
309 return (long)(u << shift);
310 }
311
312 inline static VALUE
f_gcd_normal(VALUE x,VALUE y)313 f_gcd_normal(VALUE x, VALUE y)
314 {
315 VALUE z;
316
317 if (FIXNUM_P(x) && FIXNUM_P(y))
318 return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
319
320 if (INT_NEGATIVE_P(x))
321 x = rb_int_uminus(x);
322 if (INT_NEGATIVE_P(y))
323 y = rb_int_uminus(y);
324
325 if (INT_ZERO_P(x))
326 return y;
327 if (INT_ZERO_P(y))
328 return x;
329
330 for (;;) {
331 if (FIXNUM_P(x)) {
332 if (FIXNUM_ZERO_P(x))
333 return y;
334 if (FIXNUM_P(y))
335 return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
336 }
337 z = x;
338 x = rb_int_modulo(y, x);
339 y = z;
340 }
341 /* NOTREACHED */
342 }
343
344 VALUE
rb_gcd_normal(VALUE x,VALUE y)345 rb_gcd_normal(VALUE x, VALUE y)
346 {
347 return f_gcd_normal(x, y);
348 }
349
350 inline static VALUE
f_gcd(VALUE x,VALUE y)351 f_gcd(VALUE x, VALUE y)
352 {
353 #ifdef USE_GMP
354 if (RB_TYPE_P(x, T_BIGNUM) && RB_TYPE_P(y, T_BIGNUM)) {
355 size_t xn = BIGNUM_LEN(x);
356 size_t yn = BIGNUM_LEN(y);
357 if (GMP_GCD_DIGITS <= xn || GMP_GCD_DIGITS <= yn)
358 return rb_gcd_gmp(x, y);
359 }
360 #endif
361 return f_gcd_normal(x, y);
362 }
363
364 #ifndef NDEBUG
365 #undef f_gcd
366
367 inline static VALUE
f_gcd(VALUE x,VALUE y)368 f_gcd(VALUE x, VALUE y)
369 {
370 VALUE r = f_gcd_orig(x, y);
371 if (f_nonzero_p(r)) {
372 assert(f_zero_p(f_mod(x, r)));
373 assert(f_zero_p(f_mod(y, r)));
374 }
375 return r;
376 }
377 #endif
378
379 inline static VALUE
f_lcm(VALUE x,VALUE y)380 f_lcm(VALUE x, VALUE y)
381 {
382 if (INT_ZERO_P(x) || INT_ZERO_P(y))
383 return ZERO;
384 return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
385 }
386
387 #define get_dat1(x) \
388 struct RRational *dat = RRATIONAL(x)
389
390 #define get_dat2(x,y) \
391 struct RRational *adat = RRATIONAL(x), *bdat = RRATIONAL(y)
392
393 inline static VALUE
nurat_s_new_internal(VALUE klass,VALUE num,VALUE den)394 nurat_s_new_internal(VALUE klass, VALUE num, VALUE den)
395 {
396 NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL | (RGENGC_WB_PROTECTED_RATIONAL ? FL_WB_PROTECTED : 0));
397
398 RRATIONAL_SET_NUM(obj, num);
399 RRATIONAL_SET_DEN(obj, den);
400 OBJ_FREEZE_RAW(obj);
401
402 return (VALUE)obj;
403 }
404
405 static VALUE
nurat_s_alloc(VALUE klass)406 nurat_s_alloc(VALUE klass)
407 {
408 return nurat_s_new_internal(klass, ZERO, ONE);
409 }
410
411 inline static VALUE
f_rational_new_bang1(VALUE klass,VALUE x)412 f_rational_new_bang1(VALUE klass, VALUE x)
413 {
414 return nurat_s_new_internal(klass, x, ONE);
415 }
416
417 #ifdef CANONICALIZATION_FOR_MATHN
418 static int canonicalization = 0;
419
420 RUBY_FUNC_EXPORTED void
nurat_canonicalization(int f)421 nurat_canonicalization(int f)
422 {
423 canonicalization = f;
424 }
425 #else
426 # define canonicalization 0
427 #endif
428
429 inline static void
nurat_int_check(VALUE num)430 nurat_int_check(VALUE num)
431 {
432 if (!RB_INTEGER_TYPE_P(num)) {
433 if (!k_numeric_p(num) || !f_integer_p(num))
434 rb_raise(rb_eTypeError, "not an integer");
435 }
436 }
437
438 inline static VALUE
nurat_int_value(VALUE num)439 nurat_int_value(VALUE num)
440 {
441 nurat_int_check(num);
442 if (!k_integer_p(num))
443 num = f_to_i(num);
444 return num;
445 }
446
447 static void
nurat_canonicalize(VALUE * num,VALUE * den)448 nurat_canonicalize(VALUE *num, VALUE *den)
449 {
450 assert(num); assert(RB_INTEGER_TYPE_P(*num));
451 assert(den); assert(RB_INTEGER_TYPE_P(*den));
452 if (INT_NEGATIVE_P(*den)) {
453 *num = rb_int_uminus(*num);
454 *den = rb_int_uminus(*den);
455 }
456 else if (INT_ZERO_P(*den)) {
457 rb_num_zerodiv();
458 }
459 }
460
461 static void
nurat_reduce(VALUE * x,VALUE * y)462 nurat_reduce(VALUE *x, VALUE *y)
463 {
464 VALUE gcd;
465 if (*x == ONE || *y == ONE) return;
466 gcd = f_gcd(*x, *y);
467 *x = f_idiv(*x, gcd);
468 *y = f_idiv(*y, gcd);
469 }
470
471 inline static VALUE
nurat_s_canonicalize_internal(VALUE klass,VALUE num,VALUE den)472 nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den)
473 {
474 nurat_canonicalize(&num, &den);
475 nurat_reduce(&num, &den);
476
477 if (canonicalization && f_one_p(den))
478 return num;
479 return nurat_s_new_internal(klass, num, den);
480 }
481
482 inline static VALUE
nurat_s_canonicalize_internal_no_reduce(VALUE klass,VALUE num,VALUE den)483 nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den)
484 {
485 nurat_canonicalize(&num, &den);
486
487 if (canonicalization && f_one_p(den))
488 return num;
489 return nurat_s_new_internal(klass, num, den);
490 }
491
492 static VALUE
nurat_s_new(int argc,VALUE * argv,VALUE klass)493 nurat_s_new(int argc, VALUE *argv, VALUE klass)
494 {
495 VALUE num, den;
496
497 switch (rb_scan_args(argc, argv, "11", &num, &den)) {
498 case 1:
499 num = nurat_int_value(num);
500 den = ONE;
501 break;
502 default:
503 num = nurat_int_value(num);
504 den = nurat_int_value(den);
505 break;
506 }
507
508 return nurat_s_canonicalize_internal(klass, num, den);
509 }
510
511 inline static VALUE
f_rational_new2(VALUE klass,VALUE x,VALUE y)512 f_rational_new2(VALUE klass, VALUE x, VALUE y)
513 {
514 assert(!k_rational_p(x));
515 assert(!k_rational_p(y));
516 return nurat_s_canonicalize_internal(klass, x, y);
517 }
518
519 inline static VALUE
f_rational_new_no_reduce2(VALUE klass,VALUE x,VALUE y)520 f_rational_new_no_reduce2(VALUE klass, VALUE x, VALUE y)
521 {
522 assert(!k_rational_p(x));
523 assert(!k_rational_p(y));
524 return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
525 }
526
527 static VALUE nurat_convert(VALUE klass, VALUE numv, VALUE denv, int raise);
528 static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
529
530 /*
531 * call-seq:
532 * Rational(x, y, exception: true) -> rational
533 * Rational(arg, exception: true) -> rational
534 *
535 * Returns +x/y+ or +arg+ as a Rational.
536 *
537 * Rational(2, 3) #=> (2/3)
538 * Rational(5) #=> (5/1)
539 * Rational(0.5) #=> (1/2)
540 * Rational(0.3) #=> (5404319552844595/18014398509481984)
541 *
542 * Rational("2/3") #=> (2/3)
543 * Rational("0.3") #=> (3/10)
544 *
545 * Rational("10 cents") #=> ArgumentError
546 * Rational(nil) #=> TypeError
547 * Rational(1, nil) #=> TypeError
548 *
549 * Rational("10 cents", exception: false) #=> nil
550 *
551 * Syntax of the string form:
552 *
553 * string form = extra spaces , rational , extra spaces ;
554 * rational = [ sign ] , unsigned rational ;
555 * unsigned rational = numerator | numerator , "/" , denominator ;
556 * numerator = integer part | fractional part | integer part , fractional part ;
557 * denominator = digits ;
558 * integer part = digits ;
559 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
560 * sign = "-" | "+" ;
561 * digits = digit , { digit | "_" , digit } ;
562 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
563 * extra spaces = ? \s* ? ;
564 *
565 * See also String#to_r.
566 */
567 static VALUE
nurat_f_rational(int argc,VALUE * argv,VALUE klass)568 nurat_f_rational(int argc, VALUE *argv, VALUE klass)
569 {
570 VALUE a1, a2, opts = Qnil;
571 int raise = TRUE;
572
573 if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
574 a2 = Qundef;
575 }
576 if (!NIL_P(opts)) {
577 static ID kwds[1];
578 VALUE exception;
579 if (!kwds[0]) {
580 kwds[0] = idException;
581 }
582 rb_get_kwargs(opts, kwds, 0, 1, &exception);
583 raise = (exception != Qfalse);
584 }
585 return nurat_convert(rb_cRational, a1, a2, raise);
586 }
587
588 /*
589 * call-seq:
590 * rat.numerator -> integer
591 *
592 * Returns the numerator.
593 *
594 * Rational(7).numerator #=> 7
595 * Rational(7, 1).numerator #=> 7
596 * Rational(9, -4).numerator #=> -9
597 * Rational(-2, -10).numerator #=> 1
598 */
599 static VALUE
nurat_numerator(VALUE self)600 nurat_numerator(VALUE self)
601 {
602 get_dat1(self);
603 return dat->num;
604 }
605
606 /*
607 * call-seq:
608 * rat.denominator -> integer
609 *
610 * Returns the denominator (always positive).
611 *
612 * Rational(7).denominator #=> 1
613 * Rational(7, 1).denominator #=> 1
614 * Rational(9, -4).denominator #=> 4
615 * Rational(-2, -10).denominator #=> 5
616 */
617 static VALUE
nurat_denominator(VALUE self)618 nurat_denominator(VALUE self)
619 {
620 get_dat1(self);
621 return dat->den;
622 }
623
624 /*
625 * call-seq:
626 * -rat -> rational
627 *
628 * Negates +rat+.
629 */
630 VALUE
rb_rational_uminus(VALUE self)631 rb_rational_uminus(VALUE self)
632 {
633 const int unused = (assert(RB_TYPE_P(self, T_RATIONAL)), 0);
634 get_dat1(self);
635 (void)unused;
636 return f_rational_new2(CLASS_OF(self), rb_int_uminus(dat->num), dat->den);
637 }
638
639 #ifndef NDEBUG
640 #define f_imul f_imul_orig
641 #endif
642
643 inline static VALUE
f_imul(long a,long b)644 f_imul(long a, long b)
645 {
646 VALUE r;
647
648 if (a == 0 || b == 0)
649 return ZERO;
650 else if (a == 1)
651 return LONG2NUM(b);
652 else if (b == 1)
653 return LONG2NUM(a);
654
655 if (MUL_OVERFLOW_LONG_P(a, b))
656 r = rb_big_mul(rb_int2big(a), rb_int2big(b));
657 else
658 r = LONG2NUM(a * b);
659 return r;
660 }
661
662 #ifndef NDEBUG
663 #undef f_imul
664
665 inline static VALUE
f_imul(long x,long y)666 f_imul(long x, long y)
667 {
668 VALUE r = f_imul_orig(x, y);
669 assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
670 return r;
671 }
672 #endif
673
674 inline static VALUE
f_addsub(VALUE self,VALUE anum,VALUE aden,VALUE bnum,VALUE bden,int k)675 f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
676 {
677 VALUE num, den;
678
679 if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
680 FIXNUM_P(bnum) && FIXNUM_P(bden)) {
681 long an = FIX2LONG(anum);
682 long ad = FIX2LONG(aden);
683 long bn = FIX2LONG(bnum);
684 long bd = FIX2LONG(bden);
685 long ig = i_gcd(ad, bd);
686
687 VALUE g = LONG2NUM(ig);
688 VALUE a = f_imul(an, bd / ig);
689 VALUE b = f_imul(bn, ad / ig);
690 VALUE c;
691
692 if (k == '+')
693 c = rb_int_plus(a, b);
694 else
695 c = rb_int_minus(a, b);
696
697 b = rb_int_idiv(aden, g);
698 g = f_gcd(c, g);
699 num = rb_int_idiv(c, g);
700 a = rb_int_idiv(bden, g);
701 den = rb_int_mul(a, b);
702 }
703 else if (RB_INTEGER_TYPE_P(anum) && RB_INTEGER_TYPE_P(aden) &&
704 RB_INTEGER_TYPE_P(bnum) && RB_INTEGER_TYPE_P(bden)) {
705 VALUE g = f_gcd(aden, bden);
706 VALUE a = rb_int_mul(anum, rb_int_idiv(bden, g));
707 VALUE b = rb_int_mul(bnum, rb_int_idiv(aden, g));
708 VALUE c;
709
710 if (k == '+')
711 c = rb_int_plus(a, b);
712 else
713 c = rb_int_minus(a, b);
714
715 b = rb_int_idiv(aden, g);
716 g = f_gcd(c, g);
717 num = rb_int_idiv(c, g);
718 a = rb_int_idiv(bden, g);
719 den = rb_int_mul(a, b);
720 }
721 else {
722 double a = NUM2DBL(anum) / NUM2DBL(aden);
723 double b = NUM2DBL(bnum) / NUM2DBL(bden);
724 double c = k == '+' ? a + b : a - b;
725 return DBL2NUM(c);
726 }
727 return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
728 }
729
730 static double nurat_to_double(VALUE self);
731 /*
732 * call-seq:
733 * rat + numeric -> numeric
734 *
735 * Performs addition.
736 *
737 * Rational(2, 3) + Rational(2, 3) #=> (4/3)
738 * Rational(900) + Rational(1) #=> (901/1)
739 * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18)
740 * Rational(9, 8) + 4 #=> (41/8)
741 * Rational(20, 9) + 9.8 #=> 12.022222222222222
742 */
743 VALUE
rb_rational_plus(VALUE self,VALUE other)744 rb_rational_plus(VALUE self, VALUE other)
745 {
746 if (RB_INTEGER_TYPE_P(other)) {
747 {
748 get_dat1(self);
749
750 return f_rational_new_no_reduce2(CLASS_OF(self),
751 rb_int_plus(dat->num, rb_int_mul(other, dat->den)),
752 dat->den);
753 }
754 }
755 else if (RB_FLOAT_TYPE_P(other)) {
756 return DBL2NUM(nurat_to_double(self) + RFLOAT_VALUE(other));
757 }
758 else if (RB_TYPE_P(other, T_RATIONAL)) {
759 {
760 get_dat2(self, other);
761
762 return f_addsub(self,
763 adat->num, adat->den,
764 bdat->num, bdat->den, '+');
765 }
766 }
767 else {
768 return rb_num_coerce_bin(self, other, '+');
769 }
770 }
771
772 /*
773 * call-seq:
774 * rat - numeric -> numeric
775 *
776 * Performs subtraction.
777 *
778 * Rational(2, 3) - Rational(2, 3) #=> (0/1)
779 * Rational(900) - Rational(1) #=> (899/1)
780 * Rational(-2, 9) - Rational(-9, 2) #=> (77/18)
781 * Rational(9, 8) - 4 #=> (-23/8)
782 * Rational(20, 9) - 9.8 #=> -7.577777777777778
783 */
784 VALUE
rb_rational_minus(VALUE self,VALUE other)785 rb_rational_minus(VALUE self, VALUE other)
786 {
787 if (RB_INTEGER_TYPE_P(other)) {
788 {
789 get_dat1(self);
790
791 return f_rational_new_no_reduce2(CLASS_OF(self),
792 rb_int_minus(dat->num, rb_int_mul(other, dat->den)),
793 dat->den);
794 }
795 }
796 else if (RB_FLOAT_TYPE_P(other)) {
797 return DBL2NUM(nurat_to_double(self) - RFLOAT_VALUE(other));
798 }
799 else if (RB_TYPE_P(other, T_RATIONAL)) {
800 {
801 get_dat2(self, other);
802
803 return f_addsub(self,
804 adat->num, adat->den,
805 bdat->num, bdat->den, '-');
806 }
807 }
808 else {
809 return rb_num_coerce_bin(self, other, '-');
810 }
811 }
812
813 inline static VALUE
f_muldiv(VALUE self,VALUE anum,VALUE aden,VALUE bnum,VALUE bden,int k)814 f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
815 {
816 VALUE num, den;
817
818 assert(RB_TYPE_P(self, T_RATIONAL));
819
820 /* Integer#** can return Rational with Float right now */
821 if (RB_FLOAT_TYPE_P(anum) || RB_FLOAT_TYPE_P(aden) ||
822 RB_FLOAT_TYPE_P(bnum) || RB_FLOAT_TYPE_P(bden)) {
823 double an = NUM2DBL(anum), ad = NUM2DBL(aden);
824 double bn = NUM2DBL(bnum), bd = NUM2DBL(bden);
825 double x = (an * bn) / (ad * bd);
826 return DBL2NUM(x);
827 }
828
829 assert(RB_INTEGER_TYPE_P(anum));
830 assert(RB_INTEGER_TYPE_P(aden));
831 assert(RB_INTEGER_TYPE_P(bnum));
832 assert(RB_INTEGER_TYPE_P(bden));
833
834 if (k == '/') {
835 VALUE t;
836
837 if (INT_NEGATIVE_P(bnum)) {
838 anum = rb_int_uminus(anum);
839 bnum = rb_int_uminus(bnum);
840 }
841 t = bnum;
842 bnum = bden;
843 bden = t;
844 }
845
846 if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
847 FIXNUM_P(bnum) && FIXNUM_P(bden)) {
848 long an = FIX2LONG(anum);
849 long ad = FIX2LONG(aden);
850 long bn = FIX2LONG(bnum);
851 long bd = FIX2LONG(bden);
852 long g1 = i_gcd(an, bd);
853 long g2 = i_gcd(ad, bn);
854
855 num = f_imul(an / g1, bn / g2);
856 den = f_imul(ad / g2, bd / g1);
857 }
858 else {
859 VALUE g1 = f_gcd(anum, bden);
860 VALUE g2 = f_gcd(aden, bnum);
861
862 num = rb_int_mul(rb_int_idiv(anum, g1), rb_int_idiv(bnum, g2));
863 den = rb_int_mul(rb_int_idiv(aden, g2), rb_int_idiv(bden, g1));
864 }
865 return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
866 }
867
868 /*
869 * call-seq:
870 * rat * numeric -> numeric
871 *
872 * Performs multiplication.
873 *
874 * Rational(2, 3) * Rational(2, 3) #=> (4/9)
875 * Rational(900) * Rational(1) #=> (900/1)
876 * Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
877 * Rational(9, 8) * 4 #=> (9/2)
878 * Rational(20, 9) * 9.8 #=> 21.77777777777778
879 */
880 VALUE
rb_rational_mul(VALUE self,VALUE other)881 rb_rational_mul(VALUE self, VALUE other)
882 {
883 if (RB_INTEGER_TYPE_P(other)) {
884 {
885 get_dat1(self);
886
887 return f_muldiv(self,
888 dat->num, dat->den,
889 other, ONE, '*');
890 }
891 }
892 else if (RB_FLOAT_TYPE_P(other)) {
893 return DBL2NUM(nurat_to_double(self) * RFLOAT_VALUE(other));
894 }
895 else if (RB_TYPE_P(other, T_RATIONAL)) {
896 {
897 get_dat2(self, other);
898
899 return f_muldiv(self,
900 adat->num, adat->den,
901 bdat->num, bdat->den, '*');
902 }
903 }
904 else {
905 return rb_num_coerce_bin(self, other, '*');
906 }
907 }
908
909 /*
910 * call-seq:
911 * rat / numeric -> numeric
912 * rat.quo(numeric) -> numeric
913 *
914 * Performs division.
915 *
916 * Rational(2, 3) / Rational(2, 3) #=> (1/1)
917 * Rational(900) / Rational(1) #=> (900/1)
918 * Rational(-2, 9) / Rational(-9, 2) #=> (4/81)
919 * Rational(9, 8) / 4 #=> (9/32)
920 * Rational(20, 9) / 9.8 #=> 0.22675736961451246
921 */
922 VALUE
rb_rational_div(VALUE self,VALUE other)923 rb_rational_div(VALUE self, VALUE other)
924 {
925 if (RB_INTEGER_TYPE_P(other)) {
926 if (f_zero_p(other))
927 rb_num_zerodiv();
928 {
929 get_dat1(self);
930
931 return f_muldiv(self,
932 dat->num, dat->den,
933 other, ONE, '/');
934 }
935 }
936 else if (RB_FLOAT_TYPE_P(other)) {
937 VALUE v = nurat_to_f(self);
938 return rb_flo_div_flo(v, other);
939 }
940 else if (RB_TYPE_P(other, T_RATIONAL)) {
941 if (f_zero_p(other))
942 rb_num_zerodiv();
943 {
944 get_dat2(self, other);
945
946 if (f_one_p(self))
947 return f_rational_new_no_reduce2(CLASS_OF(self),
948 bdat->den, bdat->num);
949
950 return f_muldiv(self,
951 adat->num, adat->den,
952 bdat->num, bdat->den, '/');
953 }
954 }
955 else {
956 return rb_num_coerce_bin(self, other, '/');
957 }
958 }
959
960 /*
961 * call-seq:
962 * rat.fdiv(numeric) -> float
963 *
964 * Performs division and returns the value as a Float.
965 *
966 * Rational(2, 3).fdiv(1) #=> 0.6666666666666666
967 * Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333
968 * Rational(2).fdiv(3) #=> 0.6666666666666666
969 */
970 static VALUE
nurat_fdiv(VALUE self,VALUE other)971 nurat_fdiv(VALUE self, VALUE other)
972 {
973 VALUE div;
974 if (f_zero_p(other))
975 return rb_rational_div(self, rb_float_new(0.0));
976 if (FIXNUM_P(other) && other == LONG2FIX(1))
977 return nurat_to_f(self);
978 div = rb_rational_div(self, other);
979 if (RB_TYPE_P(div, T_RATIONAL))
980 return nurat_to_f(div);
981 if (RB_FLOAT_TYPE_P(div))
982 return div;
983 return rb_funcall(div, idTo_f, 0);
984 }
985
986 inline static VALUE
f_odd_p(VALUE integer)987 f_odd_p(VALUE integer)
988 {
989 if (rb_funcall(integer, '%', 1, INT2FIX(2)) != INT2FIX(0)) {
990 return Qtrue;
991 }
992 return Qfalse;
993 }
994
995 /*
996 * call-seq:
997 * rat ** numeric -> numeric
998 *
999 * Performs exponentiation.
1000 *
1001 * Rational(2) ** Rational(3) #=> (8/1)
1002 * Rational(10) ** -2 #=> (1/100)
1003 * Rational(10) ** -2.0 #=> 0.01
1004 * Rational(-4) ** Rational(1, 2) #=> (0.0+2.0i)
1005 * Rational(1, 2) ** 0 #=> (1/1)
1006 * Rational(1, 2) ** 0.0 #=> 1.0
1007 */
1008 VALUE
rb_rational_pow(VALUE self,VALUE other)1009 rb_rational_pow(VALUE self, VALUE other)
1010 {
1011 if (k_numeric_p(other) && k_exact_zero_p(other))
1012 return f_rational_new_bang1(CLASS_OF(self), ONE);
1013
1014 if (k_rational_p(other)) {
1015 get_dat1(other);
1016
1017 if (f_one_p(dat->den))
1018 other = dat->num; /* c14n */
1019 }
1020
1021 /* Deal with special cases of 0**n and 1**n */
1022 if (k_numeric_p(other) && k_exact_p(other)) {
1023 get_dat1(self);
1024 if (f_one_p(dat->den)) {
1025 if (f_one_p(dat->num)) {
1026 return f_rational_new_bang1(CLASS_OF(self), ONE);
1027 }
1028 else if (f_minus_one_p(dat->num) && RB_INTEGER_TYPE_P(other)) {
1029 return f_rational_new_bang1(CLASS_OF(self), INT2FIX(f_odd_p(other) ? -1 : 1));
1030 }
1031 else if (INT_ZERO_P(dat->num)) {
1032 if (rb_num_negative_p(other)) {
1033 rb_num_zerodiv();
1034 }
1035 else {
1036 return f_rational_new_bang1(CLASS_OF(self), ZERO);
1037 }
1038 }
1039 }
1040 }
1041
1042 /* General case */
1043 if (FIXNUM_P(other)) {
1044 {
1045 VALUE num, den;
1046
1047 get_dat1(self);
1048
1049 if (INT_POSITIVE_P(other)) {
1050 num = rb_int_pow(dat->num, other);
1051 den = rb_int_pow(dat->den, other);
1052 }
1053 else if (INT_NEGATIVE_P(other)) {
1054 num = rb_int_pow(dat->den, rb_int_uminus(other));
1055 den = rb_int_pow(dat->num, rb_int_uminus(other));
1056 }
1057 else {
1058 num = ONE;
1059 den = ONE;
1060 }
1061 if (RB_FLOAT_TYPE_P(num)) { /* infinity due to overflow */
1062 if (RB_FLOAT_TYPE_P(den))
1063 return DBL2NUM(nan(""));
1064 return num;
1065 }
1066 if (RB_FLOAT_TYPE_P(den)) { /* infinity due to overflow */
1067 num = ZERO;
1068 den = ONE;
1069 }
1070 return f_rational_new2(CLASS_OF(self), num, den);
1071 }
1072 }
1073 else if (RB_TYPE_P(other, T_BIGNUM)) {
1074 rb_warn("in a**b, b may be too big");
1075 return rb_float_pow(nurat_to_f(self), other);
1076 }
1077 else if (RB_FLOAT_TYPE_P(other) || RB_TYPE_P(other, T_RATIONAL)) {
1078 return rb_float_pow(nurat_to_f(self), other);
1079 }
1080 else {
1081 return rb_num_coerce_bin(self, other, rb_intern("**"));
1082 }
1083 }
1084 #define nurat_expt rb_rational_pow
1085
1086 /*
1087 * call-seq:
1088 * rational <=> numeric -> -1, 0, +1, or nil
1089 *
1090 * Returns -1, 0, or +1 depending on whether +rational+ is
1091 * less than, equal to, or greater than +numeric+.
1092 *
1093 * +nil+ is returned if the two values are incomparable.
1094 *
1095 * Rational(2, 3) <=> Rational(2, 3) #=> 0
1096 * Rational(5) <=> 5 #=> 0
1097 * Rational(2, 3) <=> Rational(1, 3) #=> 1
1098 * Rational(1, 3) <=> 1 #=> -1
1099 * Rational(1, 3) <=> 0.3 #=> 1
1100 *
1101 * Rational(1, 3) <=> "0.3" #=> nil
1102 */
1103 VALUE
rb_rational_cmp(VALUE self,VALUE other)1104 rb_rational_cmp(VALUE self, VALUE other)
1105 {
1106 if (RB_INTEGER_TYPE_P(other)) {
1107 {
1108 get_dat1(self);
1109
1110 if (dat->den == LONG2FIX(1))
1111 return rb_int_cmp(dat->num, other); /* c14n */
1112 other = f_rational_new_bang1(CLASS_OF(self), other);
1113 goto other_is_rational;
1114 }
1115 }
1116 else if (RB_FLOAT_TYPE_P(other)) {
1117 return rb_dbl_cmp(nurat_to_double(self), RFLOAT_VALUE(other));
1118 }
1119 else if (RB_TYPE_P(other, T_RATIONAL)) {
1120 other_is_rational:
1121 {
1122 VALUE num1, num2;
1123
1124 get_dat2(self, other);
1125
1126 if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) &&
1127 FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) {
1128 num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den));
1129 num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den));
1130 }
1131 else {
1132 num1 = rb_int_mul(adat->num, bdat->den);
1133 num2 = rb_int_mul(bdat->num, adat->den);
1134 }
1135 return rb_int_cmp(rb_int_minus(num1, num2), ZERO);
1136 }
1137 }
1138 else {
1139 return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
1140 }
1141 }
1142
1143 /*
1144 * call-seq:
1145 * rat == object -> true or false
1146 *
1147 * Returns +true+ if +rat+ equals +object+ numerically.
1148 *
1149 * Rational(2, 3) == Rational(2, 3) #=> true
1150 * Rational(5) == 5 #=> true
1151 * Rational(0) == 0.0 #=> true
1152 * Rational('1/3') == 0.33 #=> false
1153 * Rational('1/2') == '1/2' #=> false
1154 */
1155 static VALUE
nurat_eqeq_p(VALUE self,VALUE other)1156 nurat_eqeq_p(VALUE self, VALUE other)
1157 {
1158 if (RB_INTEGER_TYPE_P(other)) {
1159 get_dat1(self);
1160
1161 if (RB_INTEGER_TYPE_P(dat->num) && RB_INTEGER_TYPE_P(dat->den)) {
1162 if (INT_ZERO_P(dat->num) && INT_ZERO_P(other))
1163 return Qtrue;
1164
1165 if (!FIXNUM_P(dat->den))
1166 return Qfalse;
1167 if (FIX2LONG(dat->den) != 1)
1168 return Qfalse;
1169 return rb_int_equal(dat->num, other);
1170 }
1171 else {
1172 const double d = nurat_to_double(self);
1173 return f_boolcast(FIXNUM_ZERO_P(rb_dbl_cmp(d, NUM2DBL(other))));
1174 }
1175 }
1176 else if (RB_FLOAT_TYPE_P(other)) {
1177 const double d = nurat_to_double(self);
1178 return f_boolcast(FIXNUM_ZERO_P(rb_dbl_cmp(d, RFLOAT_VALUE(other))));
1179 }
1180 else if (RB_TYPE_P(other, T_RATIONAL)) {
1181 {
1182 get_dat2(self, other);
1183
1184 if (INT_ZERO_P(adat->num) && INT_ZERO_P(bdat->num))
1185 return Qtrue;
1186
1187 return f_boolcast(rb_int_equal(adat->num, bdat->num) &&
1188 rb_int_equal(adat->den, bdat->den));
1189 }
1190 }
1191 else {
1192 return rb_equal(other, self);
1193 }
1194 }
1195
1196 /* :nodoc: */
1197 static VALUE
nurat_coerce(VALUE self,VALUE other)1198 nurat_coerce(VALUE self, VALUE other)
1199 {
1200 if (RB_INTEGER_TYPE_P(other)) {
1201 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
1202 }
1203 else if (RB_FLOAT_TYPE_P(other)) {
1204 return rb_assoc_new(other, nurat_to_f(self));
1205 }
1206 else if (RB_TYPE_P(other, T_RATIONAL)) {
1207 return rb_assoc_new(other, self);
1208 }
1209 else if (RB_TYPE_P(other, T_COMPLEX)) {
1210 if (k_exact_zero_p(RCOMPLEX(other)->imag))
1211 return rb_assoc_new(f_rational_new_bang1
1212 (CLASS_OF(self), RCOMPLEX(other)->real), self);
1213 else
1214 return rb_assoc_new(other, rb_Complex(self, INT2FIX(0)));
1215 }
1216
1217 rb_raise(rb_eTypeError, "%s can't be coerced into %s",
1218 rb_obj_classname(other), rb_obj_classname(self));
1219 return Qnil;
1220 }
1221
1222 /*
1223 * call-seq:
1224 * rat.positive? -> true or false
1225 *
1226 * Returns +true+ if +rat+ is greater than 0.
1227 */
1228 static VALUE
nurat_positive_p(VALUE self)1229 nurat_positive_p(VALUE self)
1230 {
1231 get_dat1(self);
1232 return f_boolcast(INT_POSITIVE_P(dat->num));
1233 }
1234
1235 /*
1236 * call-seq:
1237 * rat.negative? -> true or false
1238 *
1239 * Returns +true+ if +rat+ is less than 0.
1240 */
1241 static VALUE
nurat_negative_p(VALUE self)1242 nurat_negative_p(VALUE self)
1243 {
1244 get_dat1(self);
1245 return f_boolcast(INT_NEGATIVE_P(dat->num));
1246 }
1247
1248 /*
1249 * call-seq:
1250 * rat.abs -> rational
1251 * rat.magnitude -> rational
1252 *
1253 * Returns the absolute value of +rat+.
1254 *
1255 * (1/2r).abs #=> (1/2)
1256 * (-1/2r).abs #=> (1/2)
1257 *
1258 * Rational#magnitude is an alias for Rational#abs.
1259 */
1260
1261 VALUE
rb_rational_abs(VALUE self)1262 rb_rational_abs(VALUE self)
1263 {
1264 get_dat1(self);
1265 if (INT_NEGATIVE_P(dat->num)) {
1266 VALUE num = rb_int_abs(dat->num);
1267 return nurat_s_canonicalize_internal_no_reduce(CLASS_OF(self), num, dat->den);
1268 }
1269 return self;
1270 }
1271
1272 static VALUE
nurat_floor(VALUE self)1273 nurat_floor(VALUE self)
1274 {
1275 get_dat1(self);
1276 return rb_int_idiv(dat->num, dat->den);
1277 }
1278
1279 static VALUE
nurat_ceil(VALUE self)1280 nurat_ceil(VALUE self)
1281 {
1282 get_dat1(self);
1283 return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat->num), dat->den));
1284 }
1285
1286 /*
1287 * call-seq:
1288 * rat.to_i -> integer
1289 *
1290 * Returns the truncated value as an integer.
1291 *
1292 * Equivalent to Rational#truncate.
1293 *
1294 * Rational(2, 3).to_i #=> 0
1295 * Rational(3).to_i #=> 3
1296 * Rational(300.6).to_i #=> 300
1297 * Rational(98, 71).to_i #=> 1
1298 * Rational(-31, 2).to_i #=> -15
1299 */
1300 static VALUE
nurat_truncate(VALUE self)1301 nurat_truncate(VALUE self)
1302 {
1303 get_dat1(self);
1304 if (INT_NEGATIVE_P(dat->num))
1305 return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat->num), dat->den));
1306 return rb_int_idiv(dat->num, dat->den);
1307 }
1308
1309 static VALUE
nurat_round_half_up(VALUE self)1310 nurat_round_half_up(VALUE self)
1311 {
1312 VALUE num, den, neg;
1313
1314 get_dat1(self);
1315
1316 num = dat->num;
1317 den = dat->den;
1318 neg = INT_NEGATIVE_P(num);
1319
1320 if (neg)
1321 num = rb_int_uminus(num);
1322
1323 num = rb_int_plus(rb_int_mul(num, TWO), den);
1324 den = rb_int_mul(den, TWO);
1325 num = rb_int_idiv(num, den);
1326
1327 if (neg)
1328 num = rb_int_uminus(num);
1329
1330 return num;
1331 }
1332
1333 static VALUE
nurat_round_half_down(VALUE self)1334 nurat_round_half_down(VALUE self)
1335 {
1336 VALUE num, den, neg;
1337
1338 get_dat1(self);
1339
1340 num = dat->num;
1341 den = dat->den;
1342 neg = INT_NEGATIVE_P(num);
1343
1344 if (neg)
1345 num = rb_int_uminus(num);
1346
1347 num = rb_int_plus(rb_int_mul(num, TWO), den);
1348 num = rb_int_minus(num, ONE);
1349 den = rb_int_mul(den, TWO);
1350 num = rb_int_idiv(num, den);
1351
1352 if (neg)
1353 num = rb_int_uminus(num);
1354
1355 return num;
1356 }
1357
1358 static VALUE
nurat_round_half_even(VALUE self)1359 nurat_round_half_even(VALUE self)
1360 {
1361 VALUE num, den, neg, qr;
1362
1363 get_dat1(self);
1364
1365 num = dat->num;
1366 den = dat->den;
1367 neg = INT_NEGATIVE_P(num);
1368
1369 if (neg)
1370 num = rb_int_uminus(num);
1371
1372 num = rb_int_plus(rb_int_mul(num, TWO), den);
1373 den = rb_int_mul(den, TWO);
1374 qr = rb_int_divmod(num, den);
1375 num = RARRAY_AREF(qr, 0);
1376 if (INT_ZERO_P(RARRAY_AREF(qr, 1)))
1377 num = rb_int_and(num, LONG2FIX(((int)~1)));
1378
1379 if (neg)
1380 num = rb_int_uminus(num);
1381
1382 return num;
1383 }
1384
1385 static VALUE
f_round_common(int argc,VALUE * argv,VALUE self,VALUE (* func)(VALUE))1386 f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
1387 {
1388 VALUE n, b, s;
1389
1390 if (rb_check_arity(argc, 0, 1) == 0)
1391 return (*func)(self);
1392
1393 n = argv[0];
1394
1395 if (!k_integer_p(n))
1396 rb_raise(rb_eTypeError, "not an integer");
1397
1398 b = f_expt10(n);
1399 s = rb_rational_mul(self, b);
1400
1401 if (k_float_p(s)) {
1402 if (INT_NEGATIVE_P(n))
1403 return ZERO;
1404 return self;
1405 }
1406
1407 if (!k_rational_p(s)) {
1408 s = f_rational_new_bang1(CLASS_OF(self), s);
1409 }
1410
1411 s = (*func)(s);
1412
1413 s = rb_rational_div(f_rational_new_bang1(CLASS_OF(self), s), b);
1414
1415 if (RB_TYPE_P(s, T_RATIONAL) && FIX2INT(rb_int_cmp(n, ONE)) < 0)
1416 s = nurat_truncate(s);
1417
1418 return s;
1419 }
1420
1421 VALUE
rb_rational_floor(VALUE self,int ndigits)1422 rb_rational_floor(VALUE self, int ndigits)
1423 {
1424 if (ndigits == 0) {
1425 return nurat_floor(self);
1426 }
1427 else {
1428 VALUE n = INT2NUM(ndigits);
1429 return f_round_common(1, &n, self, nurat_floor);
1430 }
1431 }
1432
1433 /*
1434 * call-seq:
1435 * rat.floor([ndigits]) -> integer or rational
1436 *
1437 * Returns the largest number less than or equal to +rat+ with
1438 * a precision of +ndigits+ decimal digits (default: 0).
1439 *
1440 * When the precision is negative, the returned value is an integer
1441 * with at least <code>ndigits.abs</code> trailing zeros.
1442 *
1443 * Returns a rational when +ndigits+ is positive,
1444 * otherwise returns an integer.
1445 *
1446 * Rational(3).floor #=> 3
1447 * Rational(2, 3).floor #=> 0
1448 * Rational(-3, 2).floor #=> -2
1449 *
1450 * # decimal - 1 2 3 . 4 5 6
1451 * # ^ ^ ^ ^ ^ ^
1452 * # precision -3 -2 -1 0 +1 +2
1453 *
1454 * Rational('-123.456').floor(+1).to_f #=> -123.5
1455 * Rational('-123.456').floor(-1) #=> -130
1456 */
1457 static VALUE
nurat_floor_n(int argc,VALUE * argv,VALUE self)1458 nurat_floor_n(int argc, VALUE *argv, VALUE self)
1459 {
1460 return f_round_common(argc, argv, self, nurat_floor);
1461 }
1462
1463 /*
1464 * call-seq:
1465 * rat.ceil([ndigits]) -> integer or rational
1466 *
1467 * Returns the smallest number greater than or equal to +rat+ with
1468 * a precision of +ndigits+ decimal digits (default: 0).
1469 *
1470 * When the precision is negative, the returned value is an integer
1471 * with at least <code>ndigits.abs</code> trailing zeros.
1472 *
1473 * Returns a rational when +ndigits+ is positive,
1474 * otherwise returns an integer.
1475 *
1476 * Rational(3).ceil #=> 3
1477 * Rational(2, 3).ceil #=> 1
1478 * Rational(-3, 2).ceil #=> -1
1479 *
1480 * # decimal - 1 2 3 . 4 5 6
1481 * # ^ ^ ^ ^ ^ ^
1482 * # precision -3 -2 -1 0 +1 +2
1483 *
1484 * Rational('-123.456').ceil(+1).to_f #=> -123.4
1485 * Rational('-123.456').ceil(-1) #=> -120
1486 */
1487 static VALUE
nurat_ceil_n(int argc,VALUE * argv,VALUE self)1488 nurat_ceil_n(int argc, VALUE *argv, VALUE self)
1489 {
1490 return f_round_common(argc, argv, self, nurat_ceil);
1491 }
1492
1493 /*
1494 * call-seq:
1495 * rat.truncate([ndigits]) -> integer or rational
1496 *
1497 * Returns +rat+ truncated (toward zero) to
1498 * a precision of +ndigits+ decimal digits (default: 0).
1499 *
1500 * When the precision is negative, the returned value is an integer
1501 * with at least <code>ndigits.abs</code> trailing zeros.
1502 *
1503 * Returns a rational when +ndigits+ is positive,
1504 * otherwise returns an integer.
1505 *
1506 * Rational(3).truncate #=> 3
1507 * Rational(2, 3).truncate #=> 0
1508 * Rational(-3, 2).truncate #=> -1
1509 *
1510 * # decimal - 1 2 3 . 4 5 6
1511 * # ^ ^ ^ ^ ^ ^
1512 * # precision -3 -2 -1 0 +1 +2
1513 *
1514 * Rational('-123.456').truncate(+1).to_f #=> -123.4
1515 * Rational('-123.456').truncate(-1) #=> -120
1516 */
1517 static VALUE
nurat_truncate_n(int argc,VALUE * argv,VALUE self)1518 nurat_truncate_n(int argc, VALUE *argv, VALUE self)
1519 {
1520 return f_round_common(argc, argv, self, nurat_truncate);
1521 }
1522
1523 /*
1524 * call-seq:
1525 * rat.round([ndigits] [, half: mode]) -> integer or rational
1526 *
1527 * Returns +rat+ rounded to the nearest value with
1528 * a precision of +ndigits+ decimal digits (default: 0).
1529 *
1530 * When the precision is negative, the returned value is an integer
1531 * with at least <code>ndigits.abs</code> trailing zeros.
1532 *
1533 * Returns a rational when +ndigits+ is positive,
1534 * otherwise returns an integer.
1535 *
1536 * Rational(3).round #=> 3
1537 * Rational(2, 3).round #=> 1
1538 * Rational(-3, 2).round #=> -2
1539 *
1540 * # decimal - 1 2 3 . 4 5 6
1541 * # ^ ^ ^ ^ ^ ^
1542 * # precision -3 -2 -1 0 +1 +2
1543 *
1544 * Rational('-123.456').round(+1).to_f #=> -123.5
1545 * Rational('-123.456').round(-1) #=> -120
1546 *
1547 * The optional +half+ keyword argument is available
1548 * similar to Float#round.
1549 *
1550 * Rational(25, 100).round(1, half: :up) #=> (3/10)
1551 * Rational(25, 100).round(1, half: :down) #=> (1/5)
1552 * Rational(25, 100).round(1, half: :even) #=> (1/5)
1553 * Rational(35, 100).round(1, half: :up) #=> (2/5)
1554 * Rational(35, 100).round(1, half: :down) #=> (3/10)
1555 * Rational(35, 100).round(1, half: :even) #=> (2/5)
1556 * Rational(-25, 100).round(1, half: :up) #=> (-3/10)
1557 * Rational(-25, 100).round(1, half: :down) #=> (-1/5)
1558 * Rational(-25, 100).round(1, half: :even) #=> (-1/5)
1559 */
1560 static VALUE
nurat_round_n(int argc,VALUE * argv,VALUE self)1561 nurat_round_n(int argc, VALUE *argv, VALUE self)
1562 {
1563 VALUE opt;
1564 enum ruby_num_rounding_mode mode = (
1565 argc = rb_scan_args(argc, argv, "*:", NULL, &opt),
1566 rb_num_get_rounding_option(opt));
1567 VALUE (*round_func)(VALUE) = ROUND_FUNC(mode, nurat_round);
1568 return f_round_common(argc, argv, self, round_func);
1569 }
1570
1571 static double
nurat_to_double(VALUE self)1572 nurat_to_double(VALUE self)
1573 {
1574 get_dat1(self);
1575 if (!RB_INTEGER_TYPE_P(dat->num) || !RB_INTEGER_TYPE_P(dat->den)) {
1576 return NUM2DBL(dat->num) / NUM2DBL(dat->den);
1577 }
1578 return rb_int_fdiv_double(dat->num, dat->den);
1579 }
1580
1581 /*
1582 * call-seq:
1583 * rat.to_f -> float
1584 *
1585 * Returns the value as a Float.
1586 *
1587 * Rational(2).to_f #=> 2.0
1588 * Rational(9, 4).to_f #=> 2.25
1589 * Rational(-3, 4).to_f #=> -0.75
1590 * Rational(20, 3).to_f #=> 6.666666666666667
1591 */
1592 static VALUE
nurat_to_f(VALUE self)1593 nurat_to_f(VALUE self)
1594 {
1595 return DBL2NUM(nurat_to_double(self));
1596 }
1597
1598 /*
1599 * call-seq:
1600 * rat.to_r -> self
1601 *
1602 * Returns self.
1603 *
1604 * Rational(2).to_r #=> (2/1)
1605 * Rational(-8, 6).to_r #=> (-4/3)
1606 */
1607 static VALUE
nurat_to_r(VALUE self)1608 nurat_to_r(VALUE self)
1609 {
1610 return self;
1611 }
1612
1613 #define id_ceil rb_intern("ceil")
1614 #define f_ceil(x) rb_funcall((x), id_ceil, 0)
1615
1616 #define id_quo rb_intern("quo")
1617 #define f_quo(x,y) rb_funcall((x), id_quo, 1, (y))
1618
1619 #define f_reciprocal(x) f_quo(ONE, (x))
1620
1621 /*
1622 The algorithm here is the method described in CLISP. Bruno Haible has
1623 graciously given permission to use this algorithm. He says, "You can use
1624 it, if you present the following explanation of the algorithm."
1625
1626 Algorithm (recursively presented):
1627 If x is a rational number, return x.
1628 If x = 0.0, return 0.
1629 If x < 0.0, return (- (rationalize (- x))).
1630 If x > 0.0:
1631 Call (integer-decode-float x). It returns a m,e,s=1 (mantissa,
1632 exponent, sign).
1633 If m = 0 or e >= 0: return x = m*2^e.
1634 Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e
1635 with smallest possible numerator and denominator.
1636 Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e.
1637 But in this case the result will be x itself anyway, regardless of
1638 the choice of a. Therefore we can simply ignore this case.
1639 Note 2: At first, we need to consider the closed interval [a,b].
1640 but since a and b have the denominator 2^(|e|+1) whereas x itself
1641 has a denominator <= 2^|e|, we can restrict the search to the open
1642 interval (a,b).
1643 So, for given a and b (0 < a < b) we are searching a rational number
1644 y with a <= y <= b.
1645 Recursive algorithm fraction_between(a,b):
1646 c := (ceiling a)
1647 if c < b
1648 then return c ; because a <= c < b, c integer
1649 else
1650 ; a is not integer (otherwise we would have had c = a < b)
1651 k := c-1 ; k = floor(a), k < a < b <= k+1
1652 return y = k + 1/fraction_between(1/(b-k), 1/(a-k))
1653 ; note 1 <= 1/(b-k) < 1/(a-k)
1654
1655 You can see that we are actually computing a continued fraction expansion.
1656
1657 Algorithm (iterative):
1658 If x is rational, return x.
1659 Call (integer-decode-float x). It returns a m,e,s (mantissa,
1660 exponent, sign).
1661 If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.)
1662 Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1)
1663 (positive and already in lowest terms because the denominator is a
1664 power of two and the numerator is odd).
1665 Start a continued fraction expansion
1666 p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0.
1667 Loop
1668 c := (ceiling a)
1669 if c >= b
1670 then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
1671 goto Loop
1672 finally partial_quotient(c).
1673 Here partial_quotient(c) denotes the iteration
1674 i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2].
1675 At the end, return s * (p[i]/q[i]).
1676 This rational number is already in lowest terms because
1677 p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i.
1678 */
1679
1680 static void
nurat_rationalize_internal(VALUE a,VALUE b,VALUE * p,VALUE * q)1681 nurat_rationalize_internal(VALUE a, VALUE b, VALUE *p, VALUE *q)
1682 {
1683 VALUE c, k, t, p0, p1, p2, q0, q1, q2;
1684
1685 p0 = ZERO;
1686 p1 = ONE;
1687 q0 = ONE;
1688 q1 = ZERO;
1689
1690 while (1) {
1691 c = f_ceil(a);
1692 if (f_lt_p(c, b))
1693 break;
1694 k = f_sub(c, ONE);
1695 p2 = f_add(f_mul(k, p1), p0);
1696 q2 = f_add(f_mul(k, q1), q0);
1697 t = f_reciprocal(f_sub(b, k));
1698 b = f_reciprocal(f_sub(a, k));
1699 a = t;
1700 p0 = p1;
1701 q0 = q1;
1702 p1 = p2;
1703 q1 = q2;
1704 }
1705 *p = f_add(f_mul(c, p1), p0);
1706 *q = f_add(f_mul(c, q1), q0);
1707 }
1708
1709 /*
1710 * call-seq:
1711 * rat.rationalize -> self
1712 * rat.rationalize(eps) -> rational
1713 *
1714 * Returns a simpler approximation of the value if the optional
1715 * argument +eps+ is given (rat-|eps| <= result <= rat+|eps|),
1716 * self otherwise.
1717 *
1718 * r = Rational(5033165, 16777216)
1719 * r.rationalize #=> (5033165/16777216)
1720 * r.rationalize(Rational('0.01')) #=> (3/10)
1721 * r.rationalize(Rational('0.1')) #=> (1/3)
1722 */
1723 static VALUE
nurat_rationalize(int argc,VALUE * argv,VALUE self)1724 nurat_rationalize(int argc, VALUE *argv, VALUE self)
1725 {
1726 VALUE e, a, b, p, q;
1727
1728 if (rb_check_arity(argc, 0, 1) == 0)
1729 return self;
1730
1731 if (nurat_negative_p(self))
1732 return rb_rational_uminus(nurat_rationalize(argc, argv, rb_rational_uminus(self)));
1733
1734 e = f_abs(argv[0]);
1735 a = f_sub(self, e);
1736 b = f_add(self, e);
1737
1738 if (f_eqeq_p(a, b))
1739 return self;
1740
1741 nurat_rationalize_internal(a, b, &p, &q);
1742 return f_rational_new2(CLASS_OF(self), p, q);
1743 }
1744
1745 /* :nodoc: */
1746 static VALUE
nurat_hash(VALUE self)1747 nurat_hash(VALUE self)
1748 {
1749 st_index_t v, h[2];
1750 VALUE n;
1751
1752 get_dat1(self);
1753 n = rb_hash(dat->num);
1754 h[0] = NUM2LONG(n);
1755 n = rb_hash(dat->den);
1756 h[1] = NUM2LONG(n);
1757 v = rb_memhash(h, sizeof(h));
1758 return ST2FIX(v);
1759 }
1760
1761 static VALUE
f_format(VALUE self,VALUE (* func)(VALUE))1762 f_format(VALUE self, VALUE (*func)(VALUE))
1763 {
1764 VALUE s;
1765 get_dat1(self);
1766
1767 s = (*func)(dat->num);
1768 rb_str_cat2(s, "/");
1769 rb_str_concat(s, (*func)(dat->den));
1770
1771 return s;
1772 }
1773
1774 /*
1775 * call-seq:
1776 * rat.to_s -> string
1777 *
1778 * Returns the value as a string.
1779 *
1780 * Rational(2).to_s #=> "2/1"
1781 * Rational(-8, 6).to_s #=> "-4/3"
1782 * Rational('1/2').to_s #=> "1/2"
1783 */
1784 static VALUE
nurat_to_s(VALUE self)1785 nurat_to_s(VALUE self)
1786 {
1787 return f_format(self, f_to_s);
1788 }
1789
1790 /*
1791 * call-seq:
1792 * rat.inspect -> string
1793 *
1794 * Returns the value as a string for inspection.
1795 *
1796 * Rational(2).inspect #=> "(2/1)"
1797 * Rational(-8, 6).inspect #=> "(-4/3)"
1798 * Rational('1/2').inspect #=> "(1/2)"
1799 */
1800 static VALUE
nurat_inspect(VALUE self)1801 nurat_inspect(VALUE self)
1802 {
1803 VALUE s;
1804
1805 s = rb_usascii_str_new2("(");
1806 rb_str_concat(s, f_format(self, f_inspect));
1807 rb_str_cat2(s, ")");
1808
1809 return s;
1810 }
1811
1812 /* :nodoc: */
1813 static VALUE
nurat_dumper(VALUE self)1814 nurat_dumper(VALUE self)
1815 {
1816 return self;
1817 }
1818
1819 /* :nodoc: */
1820 static VALUE
nurat_loader(VALUE self,VALUE a)1821 nurat_loader(VALUE self, VALUE a)
1822 {
1823 VALUE num, den;
1824
1825 get_dat1(self);
1826 num = rb_ivar_get(a, id_i_num);
1827 den = rb_ivar_get(a, id_i_den);
1828 nurat_int_check(num);
1829 nurat_int_check(den);
1830 nurat_canonicalize(&num, &den);
1831 RRATIONAL_SET_NUM(dat, num);
1832 RRATIONAL_SET_DEN(dat, den);
1833 OBJ_FREEZE_RAW(self);
1834
1835 return self;
1836 }
1837
1838 /* :nodoc: */
1839 static VALUE
nurat_marshal_dump(VALUE self)1840 nurat_marshal_dump(VALUE self)
1841 {
1842 VALUE a;
1843 get_dat1(self);
1844
1845 a = rb_assoc_new(dat->num, dat->den);
1846 rb_copy_generic_ivar(a, self);
1847 return a;
1848 }
1849
1850 /* :nodoc: */
1851 static VALUE
nurat_marshal_load(VALUE self,VALUE a)1852 nurat_marshal_load(VALUE self, VALUE a)
1853 {
1854 VALUE num, den;
1855
1856 rb_check_frozen(self);
1857 rb_check_trusted(self);
1858
1859 Check_Type(a, T_ARRAY);
1860 if (RARRAY_LEN(a) != 2)
1861 rb_raise(rb_eArgError, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a));
1862
1863 num = RARRAY_AREF(a, 0);
1864 den = RARRAY_AREF(a, 1);
1865 nurat_int_check(num);
1866 nurat_int_check(den);
1867 nurat_canonicalize(&num, &den);
1868 rb_ivar_set(self, id_i_num, num);
1869 rb_ivar_set(self, id_i_den, den);
1870
1871 return self;
1872 }
1873
1874 /* --- */
1875
1876 VALUE
rb_rational_reciprocal(VALUE x)1877 rb_rational_reciprocal(VALUE x)
1878 {
1879 get_dat1(x);
1880 return nurat_convert(CLASS_OF(x), dat->den, dat->num, FALSE);
1881 }
1882
1883 /*
1884 * call-seq:
1885 * int.gcd(other_int) -> integer
1886 *
1887 * Returns the greatest common divisor of the two integers.
1888 * The result is always positive. 0.gcd(x) and x.gcd(0) return x.abs.
1889 *
1890 * 36.gcd(60) #=> 12
1891 * 2.gcd(2) #=> 2
1892 * 3.gcd(-7) #=> 1
1893 * ((1<<31)-1).gcd((1<<61)-1) #=> 1
1894 */
1895 VALUE
rb_gcd(VALUE self,VALUE other)1896 rb_gcd(VALUE self, VALUE other)
1897 {
1898 other = nurat_int_value(other);
1899 return f_gcd(self, other);
1900 }
1901
1902 /*
1903 * call-seq:
1904 * int.lcm(other_int) -> integer
1905 *
1906 * Returns the least common multiple of the two integers.
1907 * The result is always positive. 0.lcm(x) and x.lcm(0) return zero.
1908 *
1909 * 36.lcm(60) #=> 180
1910 * 2.lcm(2) #=> 2
1911 * 3.lcm(-7) #=> 21
1912 * ((1<<31)-1).lcm((1<<61)-1) #=> 4951760154835678088235319297
1913 */
1914 VALUE
rb_lcm(VALUE self,VALUE other)1915 rb_lcm(VALUE self, VALUE other)
1916 {
1917 other = nurat_int_value(other);
1918 return f_lcm(self, other);
1919 }
1920
1921 /*
1922 * call-seq:
1923 * int.gcdlcm(other_int) -> array
1924 *
1925 * Returns an array with the greatest common divisor and
1926 * the least common multiple of the two integers, [gcd, lcm].
1927 *
1928 * 36.gcdlcm(60) #=> [12, 180]
1929 * 2.gcdlcm(2) #=> [2, 2]
1930 * 3.gcdlcm(-7) #=> [1, 21]
1931 * ((1<<31)-1).gcdlcm((1<<61)-1) #=> [1, 4951760154835678088235319297]
1932 */
1933 VALUE
rb_gcdlcm(VALUE self,VALUE other)1934 rb_gcdlcm(VALUE self, VALUE other)
1935 {
1936 other = nurat_int_value(other);
1937 return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
1938 }
1939
1940 VALUE
rb_rational_raw(VALUE x,VALUE y)1941 rb_rational_raw(VALUE x, VALUE y)
1942 {
1943 return nurat_s_new_internal(rb_cRational, x, y);
1944 }
1945
1946 VALUE
rb_rational_new(VALUE x,VALUE y)1947 rb_rational_new(VALUE x, VALUE y)
1948 {
1949 return nurat_s_canonicalize_internal(rb_cRational, x, y);
1950 }
1951
1952 VALUE
rb_Rational(VALUE x,VALUE y)1953 rb_Rational(VALUE x, VALUE y)
1954 {
1955 VALUE a[2];
1956 a[0] = x;
1957 a[1] = y;
1958 return nurat_s_convert(2, a, rb_cRational);
1959 }
1960
1961 VALUE
rb_rational_num(VALUE rat)1962 rb_rational_num(VALUE rat)
1963 {
1964 return nurat_numerator(rat);
1965 }
1966
1967 VALUE
rb_rational_den(VALUE rat)1968 rb_rational_den(VALUE rat)
1969 {
1970 return nurat_denominator(rat);
1971 }
1972
1973 #define id_numerator rb_intern("numerator")
1974 #define f_numerator(x) rb_funcall((x), id_numerator, 0)
1975
1976 #define id_denominator rb_intern("denominator")
1977 #define f_denominator(x) rb_funcall((x), id_denominator, 0)
1978
1979 #define id_to_r idTo_r
1980 #define f_to_r(x) rb_funcall((x), id_to_r, 0)
1981
1982 /*
1983 * call-seq:
1984 * num.numerator -> integer
1985 *
1986 * Returns the numerator.
1987 */
1988 static VALUE
numeric_numerator(VALUE self)1989 numeric_numerator(VALUE self)
1990 {
1991 return f_numerator(f_to_r(self));
1992 }
1993
1994 /*
1995 * call-seq:
1996 * num.denominator -> integer
1997 *
1998 * Returns the denominator (always positive).
1999 */
2000 static VALUE
numeric_denominator(VALUE self)2001 numeric_denominator(VALUE self)
2002 {
2003 return f_denominator(f_to_r(self));
2004 }
2005
2006
2007 /*
2008 * call-seq:
2009 * num.quo(int_or_rat) -> rat
2010 * num.quo(flo) -> flo
2011 *
2012 * Returns the most exact division (rational for integers, float for floats).
2013 */
2014
2015 VALUE
rb_numeric_quo(VALUE x,VALUE y)2016 rb_numeric_quo(VALUE x, VALUE y)
2017 {
2018 if (RB_FLOAT_TYPE_P(y)) {
2019 return rb_funcall(x, rb_intern("fdiv"), 1, y);
2020 }
2021
2022 if (canonicalization) {
2023 x = rb_rational_raw1(x);
2024 }
2025 else {
2026 x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r");
2027 }
2028 return rb_rational_div(x, y);
2029 }
2030
2031 VALUE
rb_rational_canonicalize(VALUE x)2032 rb_rational_canonicalize(VALUE x)
2033 {
2034 if (RB_TYPE_P(x, T_RATIONAL)) {
2035 get_dat1(x);
2036 if (f_one_p(dat->den)) return dat->num;
2037 }
2038 return x;
2039 }
2040
2041 /*
2042 * call-seq:
2043 * int.numerator -> self
2044 *
2045 * Returns self.
2046 */
2047 static VALUE
integer_numerator(VALUE self)2048 integer_numerator(VALUE self)
2049 {
2050 return self;
2051 }
2052
2053 /*
2054 * call-seq:
2055 * int.denominator -> 1
2056 *
2057 * Returns 1.
2058 */
2059 static VALUE
integer_denominator(VALUE self)2060 integer_denominator(VALUE self)
2061 {
2062 return INT2FIX(1);
2063 }
2064
2065 static VALUE float_to_r(VALUE self);
2066 /*
2067 * call-seq:
2068 * flo.numerator -> integer
2069 *
2070 * Returns the numerator. The result is machine dependent.
2071 *
2072 * n = 0.3.numerator #=> 5404319552844595
2073 * d = 0.3.denominator #=> 18014398509481984
2074 * n.fdiv(d) #=> 0.3
2075 *
2076 * See also Float#denominator.
2077 */
2078 static VALUE
float_numerator(VALUE self)2079 float_numerator(VALUE self)
2080 {
2081 double d = RFLOAT_VALUE(self);
2082 VALUE r;
2083 if (isinf(d) || isnan(d))
2084 return self;
2085 r = float_to_r(self);
2086 if (canonicalization && k_integer_p(r)) {
2087 return r;
2088 }
2089 return nurat_numerator(r);
2090 }
2091
2092 /*
2093 * call-seq:
2094 * flo.denominator -> integer
2095 *
2096 * Returns the denominator (always positive). The result is machine
2097 * dependent.
2098 *
2099 * See also Float#numerator.
2100 */
2101 static VALUE
float_denominator(VALUE self)2102 float_denominator(VALUE self)
2103 {
2104 double d = RFLOAT_VALUE(self);
2105 VALUE r;
2106 if (isinf(d) || isnan(d))
2107 return INT2FIX(1);
2108 r = float_to_r(self);
2109 if (canonicalization && k_integer_p(r)) {
2110 return ONE;
2111 }
2112 return nurat_denominator(r);
2113 }
2114
2115 /*
2116 * call-seq:
2117 * nil.to_r -> (0/1)
2118 *
2119 * Returns zero as a rational.
2120 */
2121 static VALUE
nilclass_to_r(VALUE self)2122 nilclass_to_r(VALUE self)
2123 {
2124 return rb_rational_new1(INT2FIX(0));
2125 }
2126
2127 /*
2128 * call-seq:
2129 * nil.rationalize([eps]) -> (0/1)
2130 *
2131 * Returns zero as a rational. The optional argument +eps+ is always
2132 * ignored.
2133 */
2134 static VALUE
nilclass_rationalize(int argc,VALUE * argv,VALUE self)2135 nilclass_rationalize(int argc, VALUE *argv, VALUE self)
2136 {
2137 rb_check_arity(argc, 0, 1);
2138 return nilclass_to_r(self);
2139 }
2140
2141 /*
2142 * call-seq:
2143 * int.to_r -> rational
2144 *
2145 * Returns the value as a rational.
2146 *
2147 * 1.to_r #=> (1/1)
2148 * (1<<64).to_r #=> (18446744073709551616/1)
2149 */
2150 static VALUE
integer_to_r(VALUE self)2151 integer_to_r(VALUE self)
2152 {
2153 return rb_rational_new1(self);
2154 }
2155
2156 /*
2157 * call-seq:
2158 * int.rationalize([eps]) -> rational
2159 *
2160 * Returns the value as a rational. The optional argument +eps+ is
2161 * always ignored.
2162 */
2163 static VALUE
integer_rationalize(int argc,VALUE * argv,VALUE self)2164 integer_rationalize(int argc, VALUE *argv, VALUE self)
2165 {
2166 rb_check_arity(argc, 0, 1);
2167 return integer_to_r(self);
2168 }
2169
2170 static void
float_decode_internal(VALUE self,VALUE * rf,VALUE * rn)2171 float_decode_internal(VALUE self, VALUE *rf, VALUE *rn)
2172 {
2173 double f;
2174 int n;
2175
2176 f = frexp(RFLOAT_VALUE(self), &n);
2177 f = ldexp(f, DBL_MANT_DIG);
2178 n -= DBL_MANT_DIG;
2179 *rf = rb_dbl2big(f);
2180 *rn = INT2FIX(n);
2181 }
2182
2183 /*
2184 * call-seq:
2185 * flt.to_r -> rational
2186 *
2187 * Returns the value as a rational.
2188 *
2189 * 2.0.to_r #=> (2/1)
2190 * 2.5.to_r #=> (5/2)
2191 * -0.75.to_r #=> (-3/4)
2192 * 0.0.to_r #=> (0/1)
2193 * 0.3.to_r #=> (5404319552844595/18014398509481984)
2194 *
2195 * NOTE: 0.3.to_r isn't the same as "0.3".to_r. The latter is
2196 * equivalent to "3/10".to_r, but the former isn't so.
2197 *
2198 * 0.3.to_r == 3/10r #=> false
2199 * "0.3".to_r == 3/10r #=> true
2200 *
2201 * See also Float#rationalize.
2202 */
2203 static VALUE
float_to_r(VALUE self)2204 float_to_r(VALUE self)
2205 {
2206 VALUE f, n;
2207
2208 float_decode_internal(self, &f, &n);
2209 #if FLT_RADIX == 2
2210 {
2211 long ln = FIX2LONG(n);
2212
2213 if (ln == 0)
2214 return rb_rational_new1(f);
2215 if (ln > 0)
2216 return rb_rational_new1(rb_int_lshift(f, n));
2217 ln = -ln;
2218 return rb_rational_new2(f, rb_int_lshift(ONE, INT2FIX(ln)));
2219 }
2220 #else
2221 f = rb_int_mul(f, rb_int_pow(INT2FIX(FLT_RADIX), n));
2222 if (RB_TYPE_P(f, T_RATIONAL))
2223 return f;
2224 return rb_rational_new1(f);
2225 #endif
2226 }
2227
2228 VALUE
rb_flt_rationalize_with_prec(VALUE flt,VALUE prec)2229 rb_flt_rationalize_with_prec(VALUE flt, VALUE prec)
2230 {
2231 VALUE e, a, b, p, q;
2232
2233 e = f_abs(prec);
2234 a = f_sub(flt, e);
2235 b = f_add(flt, e);
2236
2237 if (f_eqeq_p(a, b))
2238 return float_to_r(flt);
2239
2240 nurat_rationalize_internal(a, b, &p, &q);
2241 return rb_rational_new2(p, q);
2242 }
2243
2244 VALUE
rb_flt_rationalize(VALUE flt)2245 rb_flt_rationalize(VALUE flt)
2246 {
2247 VALUE a, b, f, n, p, q;
2248
2249 float_decode_internal(flt, &f, &n);
2250 if (INT_ZERO_P(f) || FIX2INT(n) >= 0)
2251 return rb_rational_new1(rb_int_lshift(f, n));
2252
2253 #if FLT_RADIX == 2
2254 {
2255 VALUE two_times_f, den;
2256
2257 two_times_f = rb_int_mul(TWO, f);
2258 den = rb_int_lshift(ONE, rb_int_minus(ONE, n));
2259
2260 a = rb_rational_new2(rb_int_minus(two_times_f, ONE), den);
2261 b = rb_rational_new2(rb_int_plus(two_times_f, ONE), den);
2262 }
2263 #else
2264 {
2265 VALUE radix_times_f, den;
2266
2267 radix_times_f = rb_int_mul(INT2FIX(FLT_RADIX), f);
2268 den = rb_int_pow(INT2FIX(FLT_RADIX), rb_int_minus(ONE, n));
2269
2270 a = rb_rational_new2(rb_int_minus(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
2271 b = rb_rational_new2(rb_int_plus(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
2272 }
2273 #endif
2274
2275 if (nurat_eqeq_p(a, b))
2276 return float_to_r(flt);
2277
2278 nurat_rationalize_internal(a, b, &p, &q);
2279 return rb_rational_new2(p, q);
2280 }
2281
2282 /*
2283 * call-seq:
2284 * flt.rationalize([eps]) -> rational
2285 *
2286 * Returns a simpler approximation of the value (flt-|eps| <= result
2287 * <= flt+|eps|). If the optional argument +eps+ is not given,
2288 * it will be chosen automatically.
2289 *
2290 * 0.3.rationalize #=> (3/10)
2291 * 1.333.rationalize #=> (1333/1000)
2292 * 1.333.rationalize(0.01) #=> (4/3)
2293 *
2294 * See also Float#to_r.
2295 */
2296 static VALUE
float_rationalize(int argc,VALUE * argv,VALUE self)2297 float_rationalize(int argc, VALUE *argv, VALUE self)
2298 {
2299 double d = RFLOAT_VALUE(self);
2300
2301 if (d < 0.0)
2302 return rb_rational_uminus(float_rationalize(argc, argv, DBL2NUM(-d)));
2303
2304 if (rb_check_arity(argc, 0, 1)) {
2305 return rb_flt_rationalize_with_prec(self, argv[0]);
2306 }
2307 else {
2308 return rb_flt_rationalize(self);
2309 }
2310 }
2311
2312 #include <ctype.h>
2313
2314 inline static int
issign(int c)2315 issign(int c)
2316 {
2317 return (c == '-' || c == '+');
2318 }
2319
2320 static int
read_sign(const char ** s,const char * const e)2321 read_sign(const char **s, const char *const e)
2322 {
2323 int sign = '?';
2324
2325 if (*s < e && issign(**s)) {
2326 sign = **s;
2327 (*s)++;
2328 }
2329 return sign;
2330 }
2331
2332 inline static int
islettere(int c)2333 islettere(int c)
2334 {
2335 return (c == 'e' || c == 'E');
2336 }
2337
2338 static VALUE
negate_num(VALUE num)2339 negate_num(VALUE num)
2340 {
2341 if (FIXNUM_P(num)) {
2342 return rb_int_uminus(num);
2343 }
2344 else {
2345 BIGNUM_NEGATE(num);
2346 return rb_big_norm(num);
2347 }
2348 }
2349
2350 static int
read_num(const char ** s,const char * const end,VALUE * num,VALUE * nexp)2351 read_num(const char **s, const char *const end, VALUE *num, VALUE *nexp)
2352 {
2353 VALUE fp = ONE, exp, fn = ZERO, n = ZERO;
2354 int expsign = 0, ok = 0;
2355 char *e;
2356
2357 *nexp = ZERO;
2358 *num = ZERO;
2359 if (*s < end && **s != '.') {
2360 n = rb_int_parse_cstr(*s, end-*s, &e, NULL,
2361 10, RB_INT_PARSE_UNDERSCORE);
2362 if (NIL_P(n))
2363 return 0;
2364 *s = e;
2365 *num = n;
2366 ok = 1;
2367 }
2368
2369 if (*s < end && **s == '.') {
2370 size_t count = 0;
2371
2372 (*s)++;
2373 fp = rb_int_parse_cstr(*s, end-*s, &e, &count,
2374 10, RB_INT_PARSE_UNDERSCORE);
2375 if (NIL_P(fp))
2376 return 1;
2377 *s = e;
2378 {
2379 VALUE l = f_expt10(*nexp = SIZET2NUM(count));
2380 n = n == ZERO ? fp : rb_int_plus(rb_int_mul(*num, l), fp);
2381 *num = n;
2382 fn = SIZET2NUM(count);
2383 }
2384 ok = 1;
2385 }
2386
2387 if (ok && *s + 1 < end && islettere(**s)) {
2388 (*s)++;
2389 expsign = read_sign(s, end);
2390 exp = rb_int_parse_cstr(*s, end-*s, &e, NULL,
2391 10, RB_INT_PARSE_UNDERSCORE);
2392 if (NIL_P(exp))
2393 return 1;
2394 *s = e;
2395 if (exp != ZERO) {
2396 if (expsign == '-') {
2397 if (fn != ZERO) exp = rb_int_plus(exp, fn);
2398 }
2399 else {
2400 if (fn != ZERO) exp = rb_int_minus(exp, fn);
2401 exp = negate_num(exp);
2402 }
2403 *nexp = exp;
2404 }
2405 }
2406
2407 return ok;
2408 }
2409
2410 inline static const char *
skip_ws(const char * s,const char * e)2411 skip_ws(const char *s, const char *e)
2412 {
2413 while (s < e && isspace((unsigned char)*s))
2414 ++s;
2415 return s;
2416 }
2417
2418 static VALUE
parse_rat(const char * s,const char * const e,int strict,int raise)2419 parse_rat(const char *s, const char *const e, int strict, int raise)
2420 {
2421 int sign;
2422 VALUE num, den, nexp, dexp;
2423
2424 s = skip_ws(s, e);
2425 sign = read_sign(&s, e);
2426
2427 if (!read_num(&s, e, &num, &nexp)) {
2428 if (strict) return Qnil;
2429 return canonicalization ? ZERO : nurat_s_alloc(rb_cRational);
2430 }
2431 den = ONE;
2432 if (s < e && *s == '/') {
2433 s++;
2434 if (!read_num(&s, e, &den, &dexp)) {
2435 if (strict) return Qnil;
2436 den = ONE;
2437 }
2438 else if (den == ZERO) {
2439 if (!raise) return Qnil;
2440 rb_num_zerodiv();
2441 }
2442 else if (strict && skip_ws(s, e) != e) {
2443 return Qnil;
2444 }
2445 else {
2446 nexp = rb_int_minus(nexp, dexp);
2447 nurat_reduce(&num, &den);
2448 }
2449 }
2450 else if (strict && skip_ws(s, e) != e) {
2451 return Qnil;
2452 }
2453
2454 if (nexp != ZERO) {
2455 if (INT_NEGATIVE_P(nexp)) {
2456 VALUE mul;
2457 if (!FIXNUM_P(nexp)) {
2458 overflow:
2459 return sign == '-' ? DBL2NUM(-HUGE_VAL) : DBL2NUM(HUGE_VAL);
2460 }
2461 mul = f_expt10(LONG2NUM(-FIX2LONG(nexp)));
2462 if (RB_FLOAT_TYPE_P(mul)) goto overflow;
2463 num = rb_int_mul(num, mul);
2464 }
2465 else {
2466 VALUE div;
2467 if (!FIXNUM_P(nexp)) {
2468 underflow:
2469 return sign == '-' ? DBL2NUM(-0.0) : DBL2NUM(+0.0);
2470 }
2471 div = f_expt10(nexp);
2472 if (RB_FLOAT_TYPE_P(div)) goto underflow;
2473 den = rb_int_mul(den, div);
2474 }
2475 nurat_reduce(&num, &den);
2476 }
2477
2478 if (sign == '-') {
2479 num = negate_num(num);
2480 }
2481
2482 if (!canonicalization || den != ONE)
2483 num = rb_rational_raw(num, den);
2484 return num;
2485 }
2486
2487 #define FLOAT_ZERO_P(x) (rb_float_value(x) == 0.0)
2488
2489 static VALUE
string_to_r_strict(VALUE self,int raise)2490 string_to_r_strict(VALUE self, int raise)
2491 {
2492 VALUE num;
2493
2494 rb_must_asciicompat(self);
2495
2496 num = parse_rat(RSTRING_PTR(self), RSTRING_END(self), 1, raise);
2497 if (NIL_P(num)) {
2498 if (!raise) return Qnil;
2499 rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
2500 self);
2501 }
2502
2503 if (RB_FLOAT_TYPE_P(num) && !FLOAT_ZERO_P(num)) {
2504 if (!raise) return Qnil;
2505 rb_raise(rb_eFloatDomainError, "Infinity");
2506 }
2507 return num;
2508 }
2509
2510 /*
2511 * call-seq:
2512 * str.to_r -> rational
2513 *
2514 * Returns the result of interpreting leading characters in +str+
2515 * as a rational. Leading whitespace and extraneous characters
2516 * past the end of a valid number are ignored.
2517 * Digit sequences can be separated by an underscore.
2518 * If there is not a valid number at the start of +str+,
2519 * zero is returned. This method never raises an exception.
2520 *
2521 * ' 2 '.to_r #=> (2/1)
2522 * '300/2'.to_r #=> (150/1)
2523 * '-9.2'.to_r #=> (-46/5)
2524 * '-9.2e2'.to_r #=> (-920/1)
2525 * '1_234_567'.to_r #=> (1234567/1)
2526 * '21 June 09'.to_r #=> (21/1)
2527 * '21/06/09'.to_r #=> (7/2)
2528 * 'BWV 1079'.to_r #=> (0/1)
2529 *
2530 * NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is
2531 * equivalent to "3/10".to_r, but the latter isn't so.
2532 *
2533 * "0.3".to_r == 3/10r #=> true
2534 * 0.3.to_r == 3/10r #=> false
2535 *
2536 * See also Kernel#Rational.
2537 */
2538 static VALUE
string_to_r(VALUE self)2539 string_to_r(VALUE self)
2540 {
2541 VALUE num;
2542
2543 rb_must_asciicompat(self);
2544
2545 num = parse_rat(RSTRING_PTR(self), RSTRING_END(self), 0, TRUE);
2546
2547 if (RB_FLOAT_TYPE_P(num) && !FLOAT_ZERO_P(num))
2548 rb_raise(rb_eFloatDomainError, "Infinity");
2549 return num;
2550 }
2551
2552 VALUE
rb_cstr_to_rat(const char * s,int strict)2553 rb_cstr_to_rat(const char *s, int strict) /* for complex's internal */
2554 {
2555 VALUE num;
2556
2557 num = parse_rat(s, s + strlen(s), strict, TRUE);
2558
2559 if (RB_FLOAT_TYPE_P(num) && !FLOAT_ZERO_P(num))
2560 rb_raise(rb_eFloatDomainError, "Infinity");
2561 return num;
2562 }
2563
2564 static VALUE
to_rational(VALUE val)2565 to_rational(VALUE val)
2566 {
2567 return rb_convert_type_with_id(val, T_RATIONAL, "Rational", idTo_r);
2568 }
2569
2570 static VALUE
nurat_convert(VALUE klass,VALUE numv,VALUE denv,int raise)2571 nurat_convert(VALUE klass, VALUE numv, VALUE denv, int raise)
2572 {
2573 VALUE a1 = numv, a2 = denv;
2574 int state;
2575
2576 if (NIL_P(a1) || NIL_P(a2)) {
2577 if (!raise) return Qnil;
2578 rb_raise(rb_eTypeError, "can't convert nil into Rational");
2579 }
2580
2581 if (RB_TYPE_P(a1, T_COMPLEX)) {
2582 if (k_exact_zero_p(RCOMPLEX(a1)->imag))
2583 a1 = RCOMPLEX(a1)->real;
2584 }
2585
2586 if (RB_TYPE_P(a2, T_COMPLEX)) {
2587 if (k_exact_zero_p(RCOMPLEX(a2)->imag))
2588 a2 = RCOMPLEX(a2)->real;
2589 }
2590
2591 if (RB_FLOAT_TYPE_P(a1)) {
2592 a1 = float_to_r(a1);
2593 }
2594 else if (RB_TYPE_P(a1, T_STRING)) {
2595 a1 = string_to_r_strict(a1, raise);
2596 if (!raise && NIL_P(a1)) return Qnil;
2597 }
2598
2599 if (RB_FLOAT_TYPE_P(a2)) {
2600 a2 = float_to_r(a2);
2601 }
2602 else if (RB_TYPE_P(a2, T_STRING)) {
2603 a2 = string_to_r_strict(a2, raise);
2604 if (!raise && NIL_P(a2)) return Qnil;
2605 }
2606
2607 if (RB_TYPE_P(a1, T_RATIONAL)) {
2608 if (a2 == Qundef || (k_exact_one_p(a2)))
2609 return a1;
2610 }
2611
2612 if (a2 == Qundef) {
2613 if (!k_integer_p(a1)) {
2614 if (!raise) {
2615 VALUE result = rb_protect(to_rational, a1, NULL);
2616 rb_set_errinfo(Qnil);
2617 return result;
2618 }
2619 return to_rational(a1);
2620 }
2621 }
2622 else {
2623 if (!k_numeric_p(a1)) {
2624 if (!raise) {
2625 a1 = rb_protect(to_rational, a1, &state);
2626 if (state) {
2627 rb_set_errinfo(Qnil);
2628 return Qnil;
2629 }
2630 }
2631 else {
2632 a1 = rb_check_convert_type_with_id(a1, T_RATIONAL, "Rational", idTo_r);
2633 }
2634 }
2635 if (!k_numeric_p(a2)) {
2636 if (!raise) {
2637 a2 = rb_protect(to_rational, a2, &state);
2638 if (state) {
2639 rb_set_errinfo(Qnil);
2640 return Qnil;
2641 }
2642 }
2643 else {
2644 a2 = rb_check_convert_type_with_id(a2, T_RATIONAL, "Rational", idTo_r);
2645 }
2646 }
2647 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
2648 (!f_integer_p(a1) || !f_integer_p(a2)))
2649 return f_div(a1, a2);
2650 }
2651
2652 {
2653 int argc;
2654 VALUE argv2[2];
2655 argv2[0] = a1;
2656 if (a2 == Qundef) {
2657 argv2[1] = Qnil;
2658 argc = 1;
2659 }
2660 else {
2661 if (!k_integer_p(a2) && !raise) return Qnil;
2662 argv2[1] = a2;
2663 argc = 2;
2664 }
2665 return nurat_s_new(argc, argv2, klass);
2666 }
2667 }
2668
2669 static VALUE
nurat_s_convert(int argc,VALUE * argv,VALUE klass)2670 nurat_s_convert(int argc, VALUE *argv, VALUE klass)
2671 {
2672 VALUE a1, a2;
2673
2674 if (rb_scan_args(argc, argv, "11", &a1, &a2) == 1) {
2675 a2 = Qundef;
2676 }
2677
2678 return nurat_convert(klass, a1, a2, TRUE);
2679 }
2680
2681 /*
2682 * A rational number can be represented as a pair of integer numbers:
2683 * a/b (b>0), where a is the numerator and b is the denominator.
2684 * Integer a equals rational a/1 mathematically.
2685 *
2686 * In Ruby, you can create rational objects with the Kernel#Rational,
2687 * to_r, or rationalize methods or by suffixing +r+ to a literal.
2688 * The return values will be irreducible fractions.
2689 *
2690 * Rational(1) #=> (1/1)
2691 * Rational(2, 3) #=> (2/3)
2692 * Rational(4, -6) #=> (-2/3)
2693 * 3.to_r #=> (3/1)
2694 * 2/3r #=> (2/3)
2695 *
2696 * You can also create rational objects from floating-point numbers or
2697 * strings.
2698 *
2699 * Rational(0.3) #=> (5404319552844595/18014398509481984)
2700 * Rational('0.3') #=> (3/10)
2701 * Rational('2/3') #=> (2/3)
2702 *
2703 * 0.3.to_r #=> (5404319552844595/18014398509481984)
2704 * '0.3'.to_r #=> (3/10)
2705 * '2/3'.to_r #=> (2/3)
2706 * 0.3.rationalize #=> (3/10)
2707 *
2708 * A rational object is an exact number, which helps you to write
2709 * programs without any rounding errors.
2710 *
2711 * 10.times.inject(0) {|t| t + 0.1 } #=> 0.9999999999999999
2712 * 10.times.inject(0) {|t| t + Rational('0.1') } #=> (1/1)
2713 *
2714 * However, when an expression includes an inexact component (numerical value
2715 * or operation), it will produce an inexact result.
2716 *
2717 * Rational(10) / 3 #=> (10/3)
2718 * Rational(10) / 3.0 #=> 3.3333333333333335
2719 *
2720 * Rational(-8) ** Rational(1, 3)
2721 * #=> (1.0000000000000002+1.7320508075688772i)
2722 */
2723 void
Init_Rational(void)2724 Init_Rational(void)
2725 {
2726 VALUE compat;
2727 #undef rb_intern
2728 #define rb_intern(str) rb_intern_const(str)
2729
2730 id_abs = rb_intern("abs");
2731 id_idiv = rb_intern("div");
2732 id_integer_p = rb_intern("integer?");
2733 id_i_num = rb_intern("@numerator");
2734 id_i_den = rb_intern("@denominator");
2735
2736 rb_cRational = rb_define_class("Rational", rb_cNumeric);
2737
2738 rb_define_alloc_func(rb_cRational, nurat_s_alloc);
2739 rb_undef_method(CLASS_OF(rb_cRational), "allocate");
2740
2741 rb_undef_method(CLASS_OF(rb_cRational), "new");
2742
2743 rb_define_global_function("Rational", nurat_f_rational, -1);
2744
2745 rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
2746 rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
2747
2748 rb_define_method(rb_cRational, "-@", rb_rational_uminus, 0);
2749 rb_define_method(rb_cRational, "+", rb_rational_plus, 1);
2750 rb_define_method(rb_cRational, "-", rb_rational_minus, 1);
2751 rb_define_method(rb_cRational, "*", rb_rational_mul, 1);
2752 rb_define_method(rb_cRational, "/", rb_rational_div, 1);
2753 rb_define_method(rb_cRational, "quo", rb_rational_div, 1);
2754 rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
2755 rb_define_method(rb_cRational, "**", nurat_expt, 1);
2756
2757 rb_define_method(rb_cRational, "<=>", rb_rational_cmp, 1);
2758 rb_define_method(rb_cRational, "==", nurat_eqeq_p, 1);
2759 rb_define_method(rb_cRational, "coerce", nurat_coerce, 1);
2760
2761 rb_define_method(rb_cRational, "positive?", nurat_positive_p, 0);
2762 rb_define_method(rb_cRational, "negative?", nurat_negative_p, 0);
2763 rb_define_method(rb_cRational, "abs", rb_rational_abs, 0);
2764 rb_define_method(rb_cRational, "magnitude", rb_rational_abs, 0);
2765
2766 rb_define_method(rb_cRational, "floor", nurat_floor_n, -1);
2767 rb_define_method(rb_cRational, "ceil", nurat_ceil_n, -1);
2768 rb_define_method(rb_cRational, "truncate", nurat_truncate_n, -1);
2769 rb_define_method(rb_cRational, "round", nurat_round_n, -1);
2770
2771 rb_define_method(rb_cRational, "to_i", nurat_truncate, 0);
2772 rb_define_method(rb_cRational, "to_f", nurat_to_f, 0);
2773 rb_define_method(rb_cRational, "to_r", nurat_to_r, 0);
2774 rb_define_method(rb_cRational, "rationalize", nurat_rationalize, -1);
2775
2776 rb_define_method(rb_cRational, "hash", nurat_hash, 0);
2777
2778 rb_define_method(rb_cRational, "to_s", nurat_to_s, 0);
2779 rb_define_method(rb_cRational, "inspect", nurat_inspect, 0);
2780
2781 rb_define_private_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
2782 /* :nodoc: */
2783 compat = rb_define_class_under(rb_cRational, "compatible", rb_cObject);
2784 rb_define_private_method(compat, "marshal_load", nurat_marshal_load, 1);
2785 rb_marshal_define_compat(rb_cRational, compat, nurat_dumper, nurat_loader);
2786
2787 /* --- */
2788
2789 rb_define_method(rb_cInteger, "gcd", rb_gcd, 1);
2790 rb_define_method(rb_cInteger, "lcm", rb_lcm, 1);
2791 rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1);
2792
2793 rb_define_method(rb_cNumeric, "numerator", numeric_numerator, 0);
2794 rb_define_method(rb_cNumeric, "denominator", numeric_denominator, 0);
2795 rb_define_method(rb_cNumeric, "quo", rb_numeric_quo, 1);
2796
2797 rb_define_method(rb_cInteger, "numerator", integer_numerator, 0);
2798 rb_define_method(rb_cInteger, "denominator", integer_denominator, 0);
2799
2800 rb_define_method(rb_cFloat, "numerator", float_numerator, 0);
2801 rb_define_method(rb_cFloat, "denominator", float_denominator, 0);
2802
2803 rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
2804 rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1);
2805 rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
2806 rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1);
2807 rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
2808 rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1);
2809
2810 rb_define_method(rb_cString, "to_r", string_to_r, 0);
2811
2812 rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1);
2813
2814 rb_provide("rational.so"); /* for backward compatibility */
2815 }
2816
2817 /*
2818 Local variables:
2819 c-file-style: "ruby"
2820 End:
2821 */
2822