Ruby: rational.c Source File

Ruby 3.3.5p100 (2024-09-03 revision ef084cc8f4958c1b6e4ead99136631bef6d8ddba)

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