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