Ruby: rational.c Source File

Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)

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