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