Ruby: rational.c Source File

Ruby 3.4.6p54 (2025-09-16 revision dbd83256b1cec76c69756ecb8758b9e1079833de)

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