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