2 rational.c: Coded by Tadayoshi Funaba 2008-2012
4 This implementation is based on Keiju Ishitsuka's Rational library
5 which is written in ruby.
8 #include "ruby/internal/config.h"
18 #if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
25 #include "internal/array.h"
26 #include "internal/complex.h"
27 #include "internal/gc.h"
28 #include "internal/numeric.h"
29 #include "internal/object.h"
30 #include "internal/rational.h"
31 #include "ruby_assert.h"
33 #define ZERO INT2FIX(0)
34 #define ONE INT2FIX(1)
35 #define TWO INT2FIX(2)
37 #define GMP_GCD_DIGITS 1
39 #define INT_ZERO_P(x) (FIXNUM_P(x) ? FIXNUM_ZERO_P(x) : rb_bigzero_p(x))
43 static ID id_abs
, id_integer_p
,
47 #define id_to_i idTo_i
49 #define f_inspect rb_inspect
50 #define f_to_s rb_obj_as_string
52 static VALUE
nurat_to_f(VALUE self
);
53 static VALUE
float_to_r(VALUE self
);
56 f_add(VALUE x
, VALUE y
)
62 if (RB_INTEGER_TYPE_P(x
))
63 return rb_int_plus(x
, y
);
64 return rb_funcall(x
, '+', 1, y
);
68 f_div(VALUE x
, VALUE y
)
72 if (RB_INTEGER_TYPE_P(x
))
73 return rb_int_div(x
, y
);
74 return rb_funcall(x
, '/', 1, y
);
78 f_lt_p(VALUE x
, VALUE y
)
80 if (FIXNUM_P(x
) && FIXNUM_P(y
))
81 return (SIGNED_VALUE
)x
< (SIGNED_VALUE
)y
;
82 if (RB_INTEGER_TYPE_P(x
)) {
83 VALUE r
= rb_int_cmp(x
, y
);
84 if (!NIL_P(r
)) return rb_int_negative_p(r
);
86 return RTEST(rb_funcall(x
, '<', 1, y
));
90 /* f_mod is used only in f_gcd defined when NDEBUG is not defined */
92 f_mod(VALUE x
, VALUE y
)
94 if (RB_INTEGER_TYPE_P(x
))
95 return rb_int_modulo(x
, y
);
96 return rb_funcall(x
, '%', 1, y
);
101 f_mul(VALUE x
, VALUE y
)
103 if (FIXNUM_ZERO_P(y
) && RB_INTEGER_TYPE_P(x
))
105 if (y
== ONE
) return x
;
106 if (FIXNUM_ZERO_P(x
) && RB_INTEGER_TYPE_P(y
))
108 if (x
== ONE
) return y
;
109 else if (RB_INTEGER_TYPE_P(x
))
110 return rb_int_mul(x
, y
);
111 return rb_funcall(x
, '*', 1, y
);
115 f_sub(VALUE x
, VALUE y
)
117 if (FIXNUM_P(y
) && FIXNUM_ZERO_P(y
))
119 return rb_funcall(x
, '-', 1, y
);
125 if (RB_INTEGER_TYPE_P(x
))
126 return rb_int_abs(x
);
127 return rb_funcall(x
, id_abs
, 0);
134 return RB_INTEGER_TYPE_P(x
);
140 if (RB_TYPE_P(x
, T_STRING
))
141 return rb_str_to_inum(x
, 10, 0);
142 return rb_funcall(x
, id_to_i
, 0);
146 f_eqeq_p(VALUE x
, VALUE y
)
148 if (FIXNUM_P(x
) && FIXNUM_P(y
))
150 if (RB_INTEGER_TYPE_P(x
))
151 return RTEST(rb_int_equal(x
, y
));
152 return (int)rb_equal(x
, y
);
156 f_idiv(VALUE x
, VALUE y
)
158 if (RB_INTEGER_TYPE_P(x
))
159 return rb_int_idiv(x
, y
);
160 return rb_funcall(x
, id_idiv
, 1, y
);
163 #define f_expt10(x) rb_int_pow(INT2FIX(10), x)
168 if (RB_INTEGER_TYPE_P(x
)) {
169 return FIXNUM_ZERO_P(x
);
171 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
172 VALUE num
= RRATIONAL(x
)->num
;
174 return FIXNUM_ZERO_P(num
);
176 return (int)rb_equal(x
, ZERO
);
179 #define f_nonzero_p(x) (!f_zero_p(x))
184 if (RB_INTEGER_TYPE_P(x
)) {
185 return x
== LONG2FIX(1);
187 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
188 VALUE num
= RRATIONAL(x
)->num
;
189 VALUE den
= RRATIONAL(x
)->den
;
191 return num
== LONG2FIX(1) && den
== LONG2FIX(1);
193 return (int)rb_equal(x
, ONE
);
197 f_minus_one_p(VALUE x
)
199 if (RB_INTEGER_TYPE_P(x
)) {
200 return x
== LONG2FIX(-1);
202 else if (RB_BIGNUM_TYPE_P(x
)) {
205 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
206 VALUE num
= RRATIONAL(x
)->num
;
207 VALUE den
= RRATIONAL(x
)->den
;
209 return num
== LONG2FIX(-1) && den
== LONG2FIX(1);
211 return (int)rb_equal(x
, INT2FIX(-1));
215 f_kind_of_p(VALUE x
, VALUE c
)
217 return (int)rb_obj_is_kind_of(x
, c
);
223 return f_kind_of_p(x
, rb_cNumeric
);
229 return RB_INTEGER_TYPE_P(x
);
235 return RB_FLOAT_TYPE_P(x
);
239 k_rational_p(VALUE x
)
241 return RB_TYPE_P(x
, T_RATIONAL
);
244 #define k_exact_p(x) (!k_float_p(x))
245 #define k_inexact_p(x) k_float_p(x)
247 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
248 #define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
252 rb_gcd_gmp(VALUE x
, VALUE y
)
254 const size_t nails
= (sizeof(BDIGIT
)-SIZEOF_BDIGIT
)*CHAR_BIT
;
263 mpz_import(mx
, BIGNUM_LEN(x
), -1, sizeof(BDIGIT
), 0, nails
, BIGNUM_DIGITS(x
));
264 mpz_import(my
, BIGNUM_LEN(y
), -1, sizeof(BDIGIT
), 0, nails
, BIGNUM_DIGITS(y
));
271 zn
= (mpz_sizeinbase(mz
, 16) + SIZEOF_BDIGIT
*2 - 1) / (SIZEOF_BDIGIT
*2);
272 z
= rb_big_new(zn
, 1);
273 mpz_export(BIGNUM_DIGITS(z
), &count
, -1, sizeof(BDIGIT
), 0, nails
, mz
);
277 return rb_big_norm(z
);
282 #define f_gcd f_gcd_orig
286 i_gcd(long x
, long y
)
288 unsigned long u
, v
, t
;
301 u
= (unsigned long)x
;
302 v
= (unsigned long)y
;
303 for (shift
= 0; ((u
| v
) & 1) == 0; ++shift
) {
323 return (long)(u
<< shift
);
327 f_gcd_normal(VALUE x
, VALUE y
)
331 if (FIXNUM_P(x
) && FIXNUM_P(y
))
332 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
334 if (INT_NEGATIVE_P(x
))
335 x
= rb_int_uminus(x
);
336 if (INT_NEGATIVE_P(y
))
337 y
= rb_int_uminus(y
);
346 if (FIXNUM_ZERO_P(x
))
349 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
352 x
= rb_int_modulo(y
, x
);
359 rb_gcd_normal(VALUE x
, VALUE y
)
361 return f_gcd_normal(x
, y
);
365 f_gcd(VALUE x
, VALUE y
)
368 if (RB_BIGNUM_TYPE_P(x
) && RB_BIGNUM_TYPE_P(y
)) {
369 size_t xn
= BIGNUM_LEN(x
);
370 size_t yn
= BIGNUM_LEN(y
);
371 if (GMP_GCD_DIGITS
<= xn
|| GMP_GCD_DIGITS
<= yn
)
372 return rb_gcd_gmp(x
, y
);
375 return f_gcd_normal(x
, y
);
382 f_gcd(VALUE x
, VALUE y
)
384 VALUE r
= f_gcd_orig(x
, y
);
385 if (f_nonzero_p(r
)) {
386 assert(f_zero_p(f_mod(x
, r
)));
387 assert(f_zero_p(f_mod(y
, r
)));
394 f_lcm(VALUE x
, VALUE y
)
396 if (INT_ZERO_P(x
) || INT_ZERO_P(y
))
398 return f_abs(f_mul(f_div(x
, f_gcd(x
, y
)), y
));
401 #define get_dat1(x) \
402 struct RRational *dat = RRATIONAL(x)
404 #define get_dat2(x,y) \
405 struct RRational *adat = RRATIONAL(x), *bdat = RRATIONAL(y)
408 nurat_s_new_internal(VALUE klass
, VALUE num
, VALUE den
)
410 NEWOBJ_OF(obj
, struct RRational
, klass
, T_RATIONAL
| (RGENGC_WB_PROTECTED_RATIONAL
? FL_WB_PROTECTED
: 0));
412 RATIONAL_SET_NUM((VALUE
)obj
, num
);
413 RATIONAL_SET_DEN((VALUE
)obj
, den
);
414 OBJ_FREEZE_RAW((VALUE
)obj
);
420 nurat_s_alloc(VALUE klass
)
422 return nurat_s_new_internal(klass
, ZERO
, ONE
);
426 f_rational_new_bang1(VALUE klass
, VALUE x
)
428 return nurat_s_new_internal(klass
, x
, ONE
);
432 nurat_int_check(VALUE num
)
434 if (!RB_INTEGER_TYPE_P(num
)) {
435 if (!k_numeric_p(num
) || !f_integer_p(num
))
436 rb_raise(rb_eTypeError
, "not an integer");
441 nurat_int_value(VALUE num
)
443 nurat_int_check(num
);
444 if (!k_integer_p(num
))
450 nurat_canonicalize(VALUE
*num
, VALUE
*den
)
452 assert(num
); assert(RB_INTEGER_TYPE_P(*num
));
453 assert(den
); assert(RB_INTEGER_TYPE_P(*den
));
454 if (INT_NEGATIVE_P(*den
)) {
455 *num
= rb_int_uminus(*num
);
456 *den
= rb_int_uminus(*den
);
458 else if (INT_ZERO_P(*den
)) {
464 nurat_reduce(VALUE
*x
, VALUE
*y
)
467 if (*x
== ONE
|| *y
== ONE
) return;
469 *x
= f_idiv(*x
, gcd
);
470 *y
= f_idiv(*y
, gcd
);
474 nurat_s_canonicalize_internal(VALUE klass
, VALUE num
, VALUE den
)
476 nurat_canonicalize(&num
, &den
);
477 nurat_reduce(&num
, &den
);
479 return nurat_s_new_internal(klass
, num
, den
);
483 nurat_s_canonicalize_internal_no_reduce(VALUE klass
, VALUE num
, VALUE den
)
485 nurat_canonicalize(&num
, &den
);
487 return nurat_s_new_internal(klass
, num
, den
);
491 f_rational_new2(VALUE klass
, VALUE x
, VALUE y
)
493 assert(!k_rational_p(x
));
494 assert(!k_rational_p(y
));
495 return nurat_s_canonicalize_internal(klass
, x
, y
);
499 f_rational_new_no_reduce2(VALUE klass
, VALUE x
, VALUE y
)
501 assert(!k_rational_p(x
));
502 assert(!k_rational_p(y
));
503 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, y
);
506 static VALUE
nurat_convert(VALUE klass
, VALUE numv
, VALUE denv
, int raise
);
507 static VALUE
nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
);
511 * Rational(x, y, exception: true) -> rational or nil
512 * Rational(arg, exception: true) -> rational or nil
514 * Returns +x/y+ or +arg+ as a Rational.
516 * Rational(2, 3) #=> (2/3)
517 * Rational(5) #=> (5/1)
518 * Rational(0.5) #=> (1/2)
519 * Rational(0.3) #=> (5404319552844595/18014398509481984)
521 * Rational("2/3") #=> (2/3)
522 * Rational("0.3") #=> (3/10)
524 * Rational("10 cents") #=> ArgumentError
525 * Rational(nil) #=> TypeError
526 * Rational(1, nil) #=> TypeError
528 * Rational("10 cents", exception: false) #=> nil
530 * Syntax of the string form:
532 * string form = extra spaces , rational , extra spaces ;
533 * rational = [ sign ] , unsigned rational ;
534 * unsigned rational = numerator | numerator , "/" , denominator ;
535 * numerator = integer part | fractional part | integer part , fractional part ;
536 * denominator = digits ;
537 * integer part = digits ;
538 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
540 * digits = digit , { digit | "_" , digit } ;
541 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
542 * extra spaces = ? \s* ? ;
544 * See also String#to_r.
547 nurat_f_rational(int argc
, VALUE
*argv
, VALUE klass
)
549 VALUE a1
, a2
, opts
= Qnil
;
552 if (rb_scan_args(argc
, argv
, "11:", &a1
, &a2
, &opts
) == 1) {
556 raise
= rb_opts_exception_p(opts
, raise
);
558 return nurat_convert(rb_cRational
, a1
, a2
, raise
);
563 * rat.numerator -> integer
565 * Returns the numerator.
567 * Rational(7).numerator #=> 7
568 * Rational(7, 1).numerator #=> 7
569 * Rational(9, -4).numerator #=> -9
570 * Rational(-2, -10).numerator #=> 1
573 nurat_numerator(VALUE self
)
581 * rat.denominator -> integer
583 * Returns the denominator (always positive).
585 * Rational(7).denominator #=> 1
586 * Rational(7, 1).denominator #=> 1
587 * Rational(9, -4).denominator #=> 4
588 * Rational(-2, -10).denominator #=> 5
591 nurat_denominator(VALUE self
)
604 rb_rational_uminus(VALUE self
)
606 const int unused
= (assert(RB_TYPE_P(self
, T_RATIONAL
)), 0);
609 return f_rational_new2(CLASS_OF(self
), rb_int_uminus(dat
->num
), dat
->den
);
613 #define f_imul f_imul_orig
617 f_imul(long a
, long b
)
621 if (a
== 0 || b
== 0)
628 if (MUL_OVERFLOW_LONG_P(a
, b
))
629 r
= rb_big_mul(rb_int2big(a
), rb_int2big(b
));
639 f_imul(long x
, long y
)
641 VALUE r
= f_imul_orig(x
, y
);
642 assert(f_eqeq_p(r
, f_mul(LONG2NUM(x
), LONG2NUM(y
))));
648 f_addsub(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
652 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
653 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
654 long an
= FIX2LONG(anum
);
655 long ad
= FIX2LONG(aden
);
656 long bn
= FIX2LONG(bnum
);
657 long bd
= FIX2LONG(bden
);
658 long ig
= i_gcd(ad
, bd
);
660 VALUE g
= LONG2NUM(ig
);
661 VALUE a
= f_imul(an
, bd
/ ig
);
662 VALUE b
= f_imul(bn
, ad
/ ig
);
666 c
= rb_int_plus(a
, b
);
668 c
= rb_int_minus(a
, b
);
670 b
= rb_int_idiv(aden
, g
);
672 num
= rb_int_idiv(c
, g
);
673 a
= rb_int_idiv(bden
, g
);
674 den
= rb_int_mul(a
, b
);
676 else if (RB_INTEGER_TYPE_P(anum
) && RB_INTEGER_TYPE_P(aden
) &&
677 RB_INTEGER_TYPE_P(bnum
) && RB_INTEGER_TYPE_P(bden
)) {
678 VALUE g
= f_gcd(aden
, bden
);
679 VALUE a
= rb_int_mul(anum
, rb_int_idiv(bden
, g
));
680 VALUE b
= rb_int_mul(bnum
, rb_int_idiv(aden
, g
));
684 c
= rb_int_plus(a
, b
);
686 c
= rb_int_minus(a
, b
);
688 b
= rb_int_idiv(aden
, g
);
690 num
= rb_int_idiv(c
, g
);
691 a
= rb_int_idiv(bden
, g
);
692 den
= rb_int_mul(a
, b
);
695 double a
= NUM2DBL(anum
) / NUM2DBL(aden
);
696 double b
= NUM2DBL(bnum
) / NUM2DBL(bden
);
697 double c
= k
== '+' ? a
+ b
: a
- b
;
700 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
703 static double nurat_to_double(VALUE self
);
706 * rat + numeric -> numeric
710 * Rational(2, 3) + Rational(2, 3) #=> (4/3)
711 * Rational(900) + Rational(1) #=> (901/1)
712 * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18)
713 * Rational(9, 8) + 4 #=> (41/8)
714 * Rational(20, 9) + 9.8 #=> 12.022222222222222
717 rb_rational_plus(VALUE self
, VALUE other
)
719 if (RB_INTEGER_TYPE_P(other
)) {
723 return f_rational_new_no_reduce2(CLASS_OF(self
),
724 rb_int_plus(dat
->num
, rb_int_mul(other
, dat
->den
)),
728 else if (RB_FLOAT_TYPE_P(other
)) {
729 return DBL2NUM(nurat_to_double(self
) + RFLOAT_VALUE(other
));
731 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
733 get_dat2(self
, other
);
735 return f_addsub(self
,
736 adat
->num
, adat
->den
,
737 bdat
->num
, bdat
->den
, '+');
741 return rb_num_coerce_bin(self
, other
, '+');
747 * rat - numeric -> numeric
749 * Performs subtraction.
751 * Rational(2, 3) - Rational(2, 3) #=> (0/1)
752 * Rational(900) - Rational(1) #=> (899/1)
753 * Rational(-2, 9) - Rational(-9, 2) #=> (77/18)
754 * Rational(9, 8) - 4 #=> (-23/8)
755 * Rational(20, 9) - 9.8 #=> -7.577777777777778
758 rb_rational_minus(VALUE self
, VALUE other
)
760 if (RB_INTEGER_TYPE_P(other
)) {
764 return f_rational_new_no_reduce2(CLASS_OF(self
),
765 rb_int_minus(dat
->num
, rb_int_mul(other
, dat
->den
)),
769 else if (RB_FLOAT_TYPE_P(other
)) {
770 return DBL2NUM(nurat_to_double(self
) - RFLOAT_VALUE(other
));
772 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
774 get_dat2(self
, other
);
776 return f_addsub(self
,
777 adat
->num
, adat
->den
,
778 bdat
->num
, bdat
->den
, '-');
782 return rb_num_coerce_bin(self
, other
, '-');
787 f_muldiv(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
791 assert(RB_TYPE_P(self
, T_RATIONAL
));
793 /* Integer#** can return Rational with Float right now */
794 if (RB_FLOAT_TYPE_P(anum
) || RB_FLOAT_TYPE_P(aden
) ||
795 RB_FLOAT_TYPE_P(bnum
) || RB_FLOAT_TYPE_P(bden
)) {
796 double an
= NUM2DBL(anum
), ad
= NUM2DBL(aden
);
797 double bn
= NUM2DBL(bnum
), bd
= NUM2DBL(bden
);
798 double x
= (an
* bn
) / (ad
* bd
);
802 assert(RB_INTEGER_TYPE_P(anum
));
803 assert(RB_INTEGER_TYPE_P(aden
));
804 assert(RB_INTEGER_TYPE_P(bnum
));
805 assert(RB_INTEGER_TYPE_P(bden
));
810 if (INT_NEGATIVE_P(bnum
)) {
811 anum
= rb_int_uminus(anum
);
812 bnum
= rb_int_uminus(bnum
);
819 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
820 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
821 long an
= FIX2LONG(anum
);
822 long ad
= FIX2LONG(aden
);
823 long bn
= FIX2LONG(bnum
);
824 long bd
= FIX2LONG(bden
);
825 long g1
= i_gcd(an
, bd
);
826 long g2
= i_gcd(ad
, bn
);
828 num
= f_imul(an
/ g1
, bn
/ g2
);
829 den
= f_imul(ad
/ g2
, bd
/ g1
);
832 VALUE g1
= f_gcd(anum
, bden
);
833 VALUE g2
= f_gcd(aden
, bnum
);
835 num
= rb_int_mul(rb_int_idiv(anum
, g1
), rb_int_idiv(bnum
, g2
));
836 den
= rb_int_mul(rb_int_idiv(aden
, g2
), rb_int_idiv(bden
, g1
));
838 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
843 * rat * numeric -> numeric
845 * Performs multiplication.
847 * Rational(2, 3) * Rational(2, 3) #=> (4/9)
848 * Rational(900) * Rational(1) #=> (900/1)
849 * Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
850 * Rational(9, 8) * 4 #=> (9/2)
851 * Rational(20, 9) * 9.8 #=> 21.77777777777778
854 rb_rational_mul(VALUE self
, VALUE other
)
856 if (RB_INTEGER_TYPE_P(other
)) {
860 return f_muldiv(self
,
865 else if (RB_FLOAT_TYPE_P(other
)) {
866 return DBL2NUM(nurat_to_double(self
) * RFLOAT_VALUE(other
));
868 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
870 get_dat2(self
, other
);
872 return f_muldiv(self
,
873 adat
->num
, adat
->den
,
874 bdat
->num
, bdat
->den
, '*');
878 return rb_num_coerce_bin(self
, other
, '*');
884 * rat / numeric -> numeric
885 * rat.quo(numeric) -> numeric
889 * Rational(2, 3) / Rational(2, 3) #=> (1/1)
890 * Rational(900) / Rational(1) #=> (900/1)
891 * Rational(-2, 9) / Rational(-9, 2) #=> (4/81)
892 * Rational(9, 8) / 4 #=> (9/32)
893 * Rational(20, 9) / 9.8 #=> 0.22675736961451246
896 rb_rational_div(VALUE self
, VALUE other
)
898 if (RB_INTEGER_TYPE_P(other
)) {
904 return f_muldiv(self
,
909 else if (RB_FLOAT_TYPE_P(other
)) {
910 VALUE v
= nurat_to_f(self
);
911 return rb_flo_div_flo(v
, other
);
913 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
917 get_dat2(self
, other
);
920 return f_rational_new_no_reduce2(CLASS_OF(self
),
921 bdat
->den
, bdat
->num
);
923 return f_muldiv(self
,
924 adat
->num
, adat
->den
,
925 bdat
->num
, bdat
->den
, '/');
929 return rb_num_coerce_bin(self
, other
, '/');
935 * rat.fdiv(numeric) -> float
937 * Performs division and returns the value as a Float.
939 * Rational(2, 3).fdiv(1) #=> 0.6666666666666666
940 * Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333
941 * Rational(2).fdiv(3) #=> 0.6666666666666666
944 nurat_fdiv(VALUE self
, VALUE other
)
948 return rb_rational_div(self
, rb_float_new(0.0));
949 if (FIXNUM_P(other
) && other
== LONG2FIX(1))
950 return nurat_to_f(self
);
951 div
= rb_rational_div(self
, other
);
952 if (RB_TYPE_P(div
, T_RATIONAL
))
953 return nurat_to_f(div
);
954 if (RB_FLOAT_TYPE_P(div
))
956 return rb_funcall(div
, idTo_f
, 0);
961 * rat ** numeric -> numeric
963 * Performs exponentiation.
965 * Rational(2) ** Rational(3) #=> (8/1)
966 * Rational(10) ** -2 #=> (1/100)
967 * Rational(10) ** -2.0 #=> 0.01
968 * Rational(-4) ** Rational(1, 2) #=> (0.0+2.0i)
969 * Rational(1, 2) ** 0 #=> (1/1)
970 * Rational(1, 2) ** 0.0 #=> 1.0
973 rb_rational_pow(VALUE self
, VALUE other
)
975 if (k_numeric_p(other
) && k_exact_zero_p(other
))
976 return f_rational_new_bang1(CLASS_OF(self
), ONE
);
978 if (k_rational_p(other
)) {
981 if (f_one_p(dat
->den
))
982 other
= dat
->num
; /* c14n */
985 /* Deal with special cases of 0**n and 1**n */
986 if (k_numeric_p(other
) && k_exact_p(other
)) {
988 if (f_one_p(dat
->den
)) {
989 if (f_one_p(dat
->num
)) {
990 return f_rational_new_bang1(CLASS_OF(self
), ONE
);
992 else if (f_minus_one_p(dat
->num
) && RB_INTEGER_TYPE_P(other
)) {
993 return f_rational_new_bang1(CLASS_OF(self
), INT2FIX(rb_int_odd_p(other
) ? -1 : 1));
995 else if (INT_ZERO_P(dat
->num
)) {
996 if (rb_num_negative_p(other
)) {
1000 return f_rational_new_bang1(CLASS_OF(self
), ZERO
);
1007 if (FIXNUM_P(other
)) {
1013 if (INT_POSITIVE_P(other
)) {
1014 num
= rb_int_pow(dat
->num
, other
);
1015 den
= rb_int_pow(dat
->den
, other
);
1017 else if (INT_NEGATIVE_P(other
)) {
1018 num
= rb_int_pow(dat
->den
, rb_int_uminus(other
));
1019 den
= rb_int_pow(dat
->num
, rb_int_uminus(other
));
1025 if (RB_FLOAT_TYPE_P(num
)) { /* infinity due to overflow */
1026 if (RB_FLOAT_TYPE_P(den
))
1027 return DBL2NUM(nan(""));
1030 if (RB_FLOAT_TYPE_P(den
)) { /* infinity due to overflow */
1034 return f_rational_new2(CLASS_OF(self
), num
, den
);
1037 else if (RB_BIGNUM_TYPE_P(other
)) {
1038 rb_warn("in a**b, b may be too big");
1039 return rb_float_pow(nurat_to_f(self
), other
);
1041 else if (RB_FLOAT_TYPE_P(other
) || RB_TYPE_P(other
, T_RATIONAL
)) {
1042 return rb_float_pow(nurat_to_f(self
), other
);
1045 return rb_num_coerce_bin(self
, other
, idPow
);
1048 #define nurat_expt rb_rational_pow
1052 * rational <=> numeric -> -1, 0, +1, or nil
1054 * Returns -1, 0, or +1 depending on whether +rational+ is
1055 * less than, equal to, or greater than +numeric+.
1057 * +nil+ is returned if the two values are incomparable.
1059 * Rational(2, 3) <=> Rational(2, 3) #=> 0
1060 * Rational(5) <=> 5 #=> 0
1061 * Rational(2, 3) <=> Rational(1, 3) #=> 1
1062 * Rational(1, 3) <=> 1 #=> -1
1063 * Rational(1, 3) <=> 0.3 #=> 1
1065 * Rational(1, 3) <=> "0.3" #=> nil
1068 rb_rational_cmp(VALUE self
, VALUE other
)
1070 switch (TYPE(other
)) {
1076 if (dat
->den
== LONG2FIX(1))
1077 return rb_int_cmp(dat
->num
, other
); /* c14n */
1078 other
= f_rational_new_bang1(CLASS_OF(self
), other
);
1086 get_dat2(self
, other
);
1088 if (FIXNUM_P(adat
->num
) && FIXNUM_P(adat
->den
) &&
1089 FIXNUM_P(bdat
->num
) && FIXNUM_P(bdat
->den
)) {
1090 num1
= f_imul(FIX2LONG(adat
->num
), FIX2LONG(bdat
->den
));
1091 num2
= f_imul(FIX2LONG(bdat
->num
), FIX2LONG(adat
->den
));
1094 num1
= rb_int_mul(adat
->num
, bdat
->den
);
1095 num2
= rb_int_mul(bdat
->num
, adat
->den
);
1097 return rb_int_cmp(rb_int_minus(num1
, num2
), ZERO
);
1101 return rb_dbl_cmp(nurat_to_double(self
), RFLOAT_VALUE(other
));
1104 return rb_num_coerce_cmp(self
, other
, idCmp
);
1110 * rat == object -> true or false
1112 * Returns +true+ if +rat+ equals +object+ numerically.
1114 * Rational(2, 3) == Rational(2, 3) #=> true
1115 * Rational(5) == 5 #=> true
1116 * Rational(0) == 0.0 #=> true
1117 * Rational('1/3') == 0.33 #=> false
1118 * Rational('1/2') == '1/2' #=> false
1121 nurat_eqeq_p(VALUE self
, VALUE other
)
1123 if (RB_INTEGER_TYPE_P(other
)) {
1126 if (RB_INTEGER_TYPE_P(dat
->num
) && RB_INTEGER_TYPE_P(dat
->den
)) {
1127 if (INT_ZERO_P(dat
->num
) && INT_ZERO_P(other
))
1130 if (!FIXNUM_P(dat
->den
))
1132 if (FIX2LONG(dat
->den
) != 1)
1134 return rb_int_equal(dat
->num
, other
);
1137 const double d
= nurat_to_double(self
);
1138 return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d
, NUM2DBL(other
))));
1141 else if (RB_FLOAT_TYPE_P(other
)) {
1142 const double d
= nurat_to_double(self
);
1143 return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d
, RFLOAT_VALUE(other
))));
1145 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
1147 get_dat2(self
, other
);
1149 if (INT_ZERO_P(adat
->num
) && INT_ZERO_P(bdat
->num
))
1152 return RBOOL(rb_int_equal(adat
->num
, bdat
->num
) &&
1153 rb_int_equal(adat
->den
, bdat
->den
));
1157 return rb_equal(other
, self
);
1163 nurat_coerce(VALUE self
, VALUE other
)
1165 if (RB_INTEGER_TYPE_P(other
)) {
1166 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self
), other
), self
);
1168 else if (RB_FLOAT_TYPE_P(other
)) {
1169 return rb_assoc_new(other
, nurat_to_f(self
));
1171 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
1172 return rb_assoc_new(other
, self
);
1174 else if (RB_TYPE_P(other
, T_COMPLEX
)) {
1175 if (!k_exact_zero_p(RCOMPLEX(other
)->imag
))
1176 return rb_assoc_new(other
, rb_Complex(self
, INT2FIX(0)));
1177 other
= RCOMPLEX(other
)->real
;
1178 if (RB_FLOAT_TYPE_P(other
)) {
1179 other
= float_to_r(other
);
1180 RBASIC_SET_CLASS(other
, CLASS_OF(self
));
1183 other
= f_rational_new_bang1(CLASS_OF(self
), other
);
1185 return rb_assoc_new(other
, self
);
1188 rb_raise(rb_eTypeError
, "%s can't be coerced into %s",
1189 rb_obj_classname(other
), rb_obj_classname(self
));
1195 * rat.positive? -> true or false
1197 * Returns +true+ if +rat+ is greater than 0.
1200 nurat_positive_p(VALUE self
)
1203 return RBOOL(INT_POSITIVE_P(dat
->num
));
1208 * rat.negative? -> true or false
1210 * Returns +true+ if +rat+ is less than 0.
1213 nurat_negative_p(VALUE self
)
1216 return RBOOL(INT_NEGATIVE_P(dat
->num
));
1221 * rat.abs -> rational
1222 * rat.magnitude -> rational
1224 * Returns the absolute value of +rat+.
1226 * (1/2r).abs #=> (1/2)
1227 * (-1/2r).abs #=> (1/2)
1229 * Rational#magnitude is an alias for Rational#abs.
1233 rb_rational_abs(VALUE self
)
1236 if (INT_NEGATIVE_P(dat
->num
)) {
1237 VALUE num
= rb_int_abs(dat
->num
);
1238 return nurat_s_canonicalize_internal_no_reduce(CLASS_OF(self
), num
, dat
->den
);
1244 nurat_floor(VALUE self
)
1247 return rb_int_idiv(dat
->num
, dat
->den
);
1251 nurat_ceil(VALUE self
)
1254 return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat
->num
), dat
->den
));
1259 * rat.to_i -> integer
1261 * Returns the truncated value as an integer.
1263 * Equivalent to Rational#truncate.
1265 * Rational(2, 3).to_i #=> 0
1266 * Rational(3).to_i #=> 3
1267 * Rational(300.6).to_i #=> 300
1268 * Rational(98, 71).to_i #=> 1
1269 * Rational(-31, 2).to_i #=> -15
1272 nurat_truncate(VALUE self
)
1275 if (INT_NEGATIVE_P(dat
->num
))
1276 return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat
->num
), dat
->den
));
1277 return rb_int_idiv(dat
->num
, dat
->den
);
1281 nurat_round_half_up(VALUE self
)
1283 VALUE num
, den
, neg
;
1289 neg
= INT_NEGATIVE_P(num
);
1292 num
= rb_int_uminus(num
);
1294 num
= rb_int_plus(rb_int_mul(num
, TWO
), den
);
1295 den
= rb_int_mul(den
, TWO
);
1296 num
= rb_int_idiv(num
, den
);
1299 num
= rb_int_uminus(num
);
1305 nurat_round_half_down(VALUE self
)
1307 VALUE num
, den
, neg
;
1313 neg
= INT_NEGATIVE_P(num
);
1316 num
= rb_int_uminus(num
);
1318 num
= rb_int_plus(rb_int_mul(num
, TWO
), den
);
1319 num
= rb_int_minus(num
, ONE
);
1320 den
= rb_int_mul(den
, TWO
);
1321 num
= rb_int_idiv(num
, den
);
1324 num
= rb_int_uminus(num
);
1330 nurat_round_half_even(VALUE self
)
1332 VALUE num
, den
, neg
, qr
;
1338 neg
= INT_NEGATIVE_P(num
);
1341 num
= rb_int_uminus(num
);
1343 num
= rb_int_plus(rb_int_mul(num
, TWO
), den
);
1344 den
= rb_int_mul(den
, TWO
);
1345 qr
= rb_int_divmod(num
, den
);
1346 num
= RARRAY_AREF(qr
, 0);
1347 if (INT_ZERO_P(RARRAY_AREF(qr
, 1)))
1348 num
= rb_int_and(num
, LONG2FIX(((int)~1)));
1351 num
= rb_int_uminus(num
);
1357 f_round_common(int argc
, VALUE
*argv
, VALUE self
, VALUE (*func
)(VALUE
))
1361 if (rb_check_arity(argc
, 0, 1) == 0)
1362 return (*func
)(self
);
1366 if (!k_integer_p(n
))
1367 rb_raise(rb_eTypeError
, "not an integer");
1370 s
= rb_rational_mul(self
, b
);
1373 if (INT_NEGATIVE_P(n
))
1378 if (!k_rational_p(s
)) {
1379 s
= f_rational_new_bang1(CLASS_OF(self
), s
);
1384 s
= rb_rational_div(f_rational_new_bang1(CLASS_OF(self
), s
), b
);
1386 if (RB_TYPE_P(s
, T_RATIONAL
) && FIX2INT(rb_int_cmp(n
, ONE
)) < 0)
1387 s
= nurat_truncate(s
);
1393 rb_rational_floor(VALUE self
, int ndigits
)
1396 return nurat_floor(self
);
1399 VALUE n
= INT2NUM(ndigits
);
1400 return f_round_common(1, &n
, self
, nurat_floor
);
1406 * rat.floor([ndigits]) -> integer or rational
1408 * Returns the largest number less than or equal to +rat+ with
1409 * a precision of +ndigits+ decimal digits (default: 0).
1411 * When the precision is negative, the returned value is an integer
1412 * with at least <code>ndigits.abs</code> trailing zeros.
1414 * Returns a rational when +ndigits+ is positive,
1415 * otherwise returns an integer.
1417 * Rational(3).floor #=> 3
1418 * Rational(2, 3).floor #=> 0
1419 * Rational(-3, 2).floor #=> -2
1421 * # decimal - 1 2 3 . 4 5 6
1423 * # precision -3 -2 -1 0 +1 +2
1425 * Rational('-123.456').floor(+1).to_f #=> -123.5
1426 * Rational('-123.456').floor(-1) #=> -130
1429 nurat_floor_n(int argc
, VALUE
*argv
, VALUE self
)
1431 return f_round_common(argc
, argv
, self
, nurat_floor
);
1436 * rat.ceil([ndigits]) -> integer or rational
1438 * Returns the smallest number greater than or equal to +rat+ with
1439 * a precision of +ndigits+ decimal digits (default: 0).
1441 * When the precision is negative, the returned value is an integer
1442 * with at least <code>ndigits.abs</code> trailing zeros.
1444 * Returns a rational when +ndigits+ is positive,
1445 * otherwise returns an integer.
1447 * Rational(3).ceil #=> 3
1448 * Rational(2, 3).ceil #=> 1
1449 * Rational(-3, 2).ceil #=> -1
1451 * # decimal - 1 2 3 . 4 5 6
1453 * # precision -3 -2 -1 0 +1 +2
1455 * Rational('-123.456').ceil(+1).to_f #=> -123.4
1456 * Rational('-123.456').ceil(-1) #=> -120
1459 nurat_ceil_n(int argc
, VALUE
*argv
, VALUE self
)
1461 return f_round_common(argc
, argv
, self
, nurat_ceil
);
1466 * rat.truncate([ndigits]) -> integer or rational
1468 * Returns +rat+ truncated (toward zero) to
1469 * a precision of +ndigits+ decimal digits (default: 0).
1471 * When the precision is negative, the returned value is an integer
1472 * with at least <code>ndigits.abs</code> trailing zeros.
1474 * Returns a rational when +ndigits+ is positive,
1475 * otherwise returns an integer.
1477 * Rational(3).truncate #=> 3
1478 * Rational(2, 3).truncate #=> 0
1479 * Rational(-3, 2).truncate #=> -1
1481 * # decimal - 1 2 3 . 4 5 6
1483 * # precision -3 -2 -1 0 +1 +2
1485 * Rational('-123.456').truncate(+1).to_f #=> -123.4
1486 * Rational('-123.456').truncate(-1) #=> -120
1489 nurat_truncate_n(int argc
, VALUE
*argv
, VALUE self
)
1491 return f_round_common(argc
, argv
, self
, nurat_truncate
);
1496 * rat.round([ndigits] [, half: mode]) -> integer or rational
1498 * Returns +rat+ rounded to the nearest value with
1499 * a precision of +ndigits+ decimal digits (default: 0).
1501 * When the precision is negative, the returned value is an integer
1502 * with at least <code>ndigits.abs</code> trailing zeros.
1504 * Returns a rational when +ndigits+ is positive,
1505 * otherwise returns an integer.
1507 * Rational(3).round #=> 3
1508 * Rational(2, 3).round #=> 1
1509 * Rational(-3, 2).round #=> -2
1511 * # decimal - 1 2 3 . 4 5 6
1513 * # precision -3 -2 -1 0 +1 +2
1515 * Rational('-123.456').round(+1).to_f #=> -123.5
1516 * Rational('-123.456').round(-1) #=> -120
1518 * The optional +half+ keyword argument is available
1519 * similar to Float#round.
1521 * Rational(25, 100).round(1, half: :up) #=> (3/10)
1522 * Rational(25, 100).round(1, half: :down) #=> (1/5)
1523 * Rational(25, 100).round(1, half: :even) #=> (1/5)
1524 * Rational(35, 100).round(1, half: :up) #=> (2/5)
1525 * Rational(35, 100).round(1, half: :down) #=> (3/10)
1526 * Rational(35, 100).round(1, half: :even) #=> (2/5)
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)
1532 nurat_round_n(int argc
, VALUE
*argv
, VALUE self
)
1535 enum ruby_num_rounding_mode mode
= (
1536 argc
= rb_scan_args(argc
, argv
, "*:", NULL
, &opt
),
1537 rb_num_get_rounding_option(opt
));
1538 VALUE (*round_func
)(VALUE
) = ROUND_FUNC(mode
, nurat_round
);
1539 return f_round_common(argc
, argv
, self
, round_func
);
1543 rb_flo_round_by_rational(int argc
, VALUE
*argv
, VALUE num
)
1545 return nurat_to_f(nurat_round_n(argc
, argv
, float_to_r(num
)));
1549 nurat_to_double(VALUE self
)
1552 if (!RB_INTEGER_TYPE_P(dat
->num
) || !RB_INTEGER_TYPE_P(dat
->den
)) {
1553 return NUM2DBL(dat
->num
) / NUM2DBL(dat
->den
);
1555 return rb_int_fdiv_double(dat
->num
, dat
->den
);
1562 * Returns the value as a Float.
1564 * Rational(2).to_f #=> 2.0
1565 * Rational(9, 4).to_f #=> 2.25
1566 * Rational(-3, 4).to_f #=> -0.75
1567 * Rational(20, 3).to_f #=> 6.666666666666667
1570 nurat_to_f(VALUE self
)
1572 return DBL2NUM(nurat_to_double(self
));
1581 * Rational(2).to_r #=> (2/1)
1582 * Rational(-8, 6).to_r #=> (-4/3)
1585 nurat_to_r(VALUE self
)
1590 #define id_ceil rb_intern("ceil")
1594 if (RB_INTEGER_TYPE_P(x
))
1596 if (RB_FLOAT_TYPE_P(x
))
1597 return rb_float_ceil(x
, 0);
1599 return rb_funcall(x
, id_ceil
, 0);
1602 #define id_quo idQuo
1604 f_quo(VALUE x
, VALUE y
)
1606 if (RB_INTEGER_TYPE_P(x
))
1607 return rb_int_div(x
, y
);
1608 if (RB_FLOAT_TYPE_P(x
))
1609 return DBL2NUM(RFLOAT_VALUE(x
) / RFLOAT_VALUE(y
));
1611 return rb_funcallv(x
, id_quo
, 1, &y
);
1614 #define f_reciprocal(x) f_quo(ONE, (x))
1617 The algorithm here is the method described in CLISP. Bruno Haible has
1618 graciously given permission to use this algorithm. He says, "You can use
1619 it, if you present the following explanation of the algorithm."
1621 Algorithm (recursively presented):
1622 If x is a rational number, return x.
1623 If x = 0.0, return 0.
1624 If x < 0.0, return (- (rationalize (- x))).
1626 Call (integer-decode-float x). It returns a m,e,s=1 (mantissa,
1628 If m = 0 or e >= 0: return x = m*2^e.
1629 Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e
1630 with smallest possible numerator and denominator.
1631 Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e.
1632 But in this case the result will be x itself anyway, regardless of
1633 the choice of a. Therefore we can simply ignore this case.
1634 Note 2: At first, we need to consider the closed interval [a,b].
1635 but since a and b have the denominator 2^(|e|+1) whereas x itself
1636 has a denominator <= 2^|e|, we can restrict the search to the open
1638 So, for given a and b (0 < a < b) we are searching a rational number
1640 Recursive algorithm fraction_between(a,b):
1643 then return c ; because a <= c < b, c integer
1645 ; a is not integer (otherwise we would have had c = a < b)
1646 k := c-1 ; k = floor(a), k < a < b <= k+1
1647 return y = k + 1/fraction_between(1/(b-k), 1/(a-k))
1648 ; note 1 <= 1/(b-k) < 1/(a-k)
1650 You can see that we are actually computing a continued fraction expansion.
1652 Algorithm (iterative):
1653 If x is rational, return x.
1654 Call (integer-decode-float x). It returns a m,e,s (mantissa,
1656 If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.)
1657 Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1)
1658 (positive and already in lowest terms because the denominator is a
1659 power of two and the numerator is odd).
1660 Start a continued fraction expansion
1661 p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0.
1665 then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
1667 finally partial_quotient(c).
1668 Here partial_quotient(c) denotes the iteration
1669 i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2].
1670 At the end, return s * (p[i]/q[i]).
1671 This rational number is already in lowest terms because
1672 p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i.
1676 nurat_rationalize_internal(VALUE a
, VALUE b
, VALUE
*p
, VALUE
*q
)
1678 VALUE c
, k
, t
, p0
, p1
, p2
, q0
, q1
, q2
;
1690 p2
= f_add(f_mul(k
, p1
), p0
);
1691 q2
= f_add(f_mul(k
, q1
), q0
);
1692 t
= f_reciprocal(f_sub(b
, k
));
1693 b
= f_reciprocal(f_sub(a
, k
));
1700 *p
= f_add(f_mul(c
, p1
), p0
);
1701 *q
= f_add(f_mul(c
, q1
), q0
);
1706 * rat.rationalize -> self
1707 * rat.rationalize(eps) -> rational
1709 * Returns a simpler approximation of the value if the optional
1710 * argument +eps+ is given (rat-|eps| <= result <= rat+|eps|),
1713 * r = Rational(5033165, 16777216)
1714 * r.rationalize #=> (5033165/16777216)
1715 * r.rationalize(Rational('0.01')) #=> (3/10)
1716 * r.rationalize(Rational('0.1')) #=> (1/3)
1719 nurat_rationalize(int argc
, VALUE
*argv
, VALUE self
)
1721 VALUE e
, a
, b
, p
, q
;
1725 if (rb_check_arity(argc
, 0, 1) == 0)
1730 if (INT_NEGATIVE_P(dat
->num
)) {
1731 rat
= f_rational_new2(RBASIC_CLASS(self
), rb_int_uminus(dat
->num
), dat
->den
);
1734 a
= FIXNUM_ZERO_P(e
) ? rat
: rb_rational_minus(rat
, e
);
1735 b
= FIXNUM_ZERO_P(e
) ? rat
: rb_rational_plus(rat
, e
);
1740 nurat_rationalize_internal(a
, b
, &p
, &q
);
1742 RATIONAL_SET_NUM(rat
, rb_int_uminus(p
));
1743 RATIONAL_SET_DEN(rat
, q
);
1746 return f_rational_new2(CLASS_OF(self
), p
, q
);
1751 rb_rational_hash(VALUE self
)
1757 n
= rb_hash(dat
->num
);
1759 n
= rb_hash(dat
->den
);
1761 v
= rb_memhash(h
, sizeof(h
));
1766 nurat_hash(VALUE self
)
1768 return ST2FIX(rb_rational_hash(self
));
1773 f_format(VALUE self
, VALUE (*func
)(VALUE
))
1778 s
= (*func
)(dat
->num
);
1779 rb_str_cat2(s
, "/");
1780 rb_str_concat(s
, (*func
)(dat
->den
));
1787 * rat.to_s -> string
1789 * Returns the value as a string.
1791 * Rational(2).to_s #=> "2/1"
1792 * Rational(-8, 6).to_s #=> "-4/3"
1793 * Rational('1/2').to_s #=> "1/2"
1796 nurat_to_s(VALUE self
)
1798 return f_format(self
, f_to_s
);
1803 * rat.inspect -> string
1805 * Returns the value as a string for inspection.
1807 * Rational(2).inspect #=> "(2/1)"
1808 * Rational(-8, 6).inspect #=> "(-4/3)"
1809 * Rational('1/2').inspect #=> "(1/2)"
1812 nurat_inspect(VALUE self
)
1816 s
= rb_usascii_str_new2("(");
1817 rb_str_concat(s
, f_format(self
, f_inspect
));
1818 rb_str_cat2(s
, ")");
1825 nurat_dumper(VALUE self
)
1832 nurat_loader(VALUE self
, VALUE a
)
1837 num
= rb_ivar_get(a
, id_i_num
);
1838 den
= rb_ivar_get(a
, id_i_den
);
1839 nurat_int_check(num
);
1840 nurat_int_check(den
);
1841 nurat_canonicalize(&num
, &den
);
1842 RATIONAL_SET_NUM((VALUE
)dat
, num
);
1843 RATIONAL_SET_DEN((VALUE
)dat
, den
);
1844 OBJ_FREEZE_RAW(self
);
1851 nurat_marshal_dump(VALUE self
)
1856 a
= rb_assoc_new(dat
->num
, dat
->den
);
1857 rb_copy_generic_ivar(a
, self
);
1863 nurat_marshal_load(VALUE self
, VALUE a
)
1867 rb_check_frozen(self
);
1869 Check_Type(a
, T_ARRAY
);
1870 if (RARRAY_LEN(a
) != 2)
1871 rb_raise(rb_eArgError
, "marshaled rational must have an array whose length is 2 but %ld", RARRAY_LEN(a
));
1873 num
= RARRAY_AREF(a
, 0);
1874 den
= RARRAY_AREF(a
, 1);
1875 nurat_int_check(num
);
1876 nurat_int_check(den
);
1877 nurat_canonicalize(&num
, &den
);
1878 rb_ivar_set(self
, id_i_num
, num
);
1879 rb_ivar_set(self
, id_i_den
, den
);
1885 rb_rational_reciprocal(VALUE x
)
1888 return nurat_convert(CLASS_OF(x
), dat
->den
, dat
->num
, FALSE
);
1893 * int.gcd(other_int) -> integer
1895 * Returns the greatest common divisor of the two integers.
1896 * The result is always positive. 0.gcd(x) and x.gcd(0) return x.abs.
1901 * ((1<<31)-1).gcd((1<<61)-1) #=> 1
1904 rb_gcd(VALUE self
, VALUE other
)
1906 other
= nurat_int_value(other
);
1907 return f_gcd(self
, other
);
1912 * int.lcm(other_int) -> integer
1914 * Returns the least common multiple of the two integers.
1915 * The result is always positive. 0.lcm(x) and x.lcm(0) return zero.
1917 * 36.lcm(60) #=> 180
1920 * ((1<<31)-1).lcm((1<<61)-1) #=> 4951760154835678088235319297
1923 rb_lcm(VALUE self
, VALUE other
)
1925 other
= nurat_int_value(other
);
1926 return f_lcm(self
, other
);
1931 * int.gcdlcm(other_int) -> array
1933 * Returns an array with the greatest common divisor and
1934 * the least common multiple of the two integers, [gcd, lcm].
1936 * 36.gcdlcm(60) #=> [12, 180]
1937 * 2.gcdlcm(2) #=> [2, 2]
1938 * 3.gcdlcm(-7) #=> [1, 21]
1939 * ((1<<31)-1).gcdlcm((1<<61)-1) #=> [1, 4951760154835678088235319297]
1942 rb_gcdlcm(VALUE self
, VALUE other
)
1944 other
= nurat_int_value(other
);
1945 return rb_assoc_new(f_gcd(self
, other
), f_lcm(self
, other
));
1949 rb_rational_raw(VALUE x
, VALUE y
)
1951 if (! RB_INTEGER_TYPE_P(x
))
1953 if (! RB_INTEGER_TYPE_P(y
))
1955 if (INT_NEGATIVE_P(y
)) {
1956 x
= rb_int_uminus(x
);
1957 y
= rb_int_uminus(y
);
1959 return nurat_s_new_internal(rb_cRational
, x
, y
);
1963 rb_rational_new(VALUE x
, VALUE y
)
1965 return nurat_s_canonicalize_internal(rb_cRational
, x
, y
);
1969 rb_Rational(VALUE x
, VALUE y
)
1974 return nurat_s_convert(2, a
, rb_cRational
);
1978 rb_rational_num(VALUE rat
)
1980 return nurat_numerator(rat
);
1984 rb_rational_den(VALUE rat
)
1986 return nurat_denominator(rat
);
1989 #define id_numerator rb_intern("numerator")
1990 #define f_numerator(x) rb_funcall((x), id_numerator, 0)
1992 #define id_denominator rb_intern("denominator")
1993 #define f_denominator(x) rb_funcall((x), id_denominator, 0)
1995 #define id_to_r idTo_r
1996 #define f_to_r(x) rb_funcall((x), id_to_r, 0)
2000 * num.numerator -> integer
2002 * Returns the numerator.
2005 numeric_numerator(VALUE self
)
2007 return f_numerator(f_to_r(self
));
2012 * num.denominator -> integer
2014 * Returns the denominator (always positive).
2017 numeric_denominator(VALUE self
)
2019 return f_denominator(f_to_r(self
));
2025 * num.quo(int_or_rat) -> rat
2026 * num.quo(flo) -> flo
2028 * Returns the most exact division (rational for integers, float for floats).
2032 rb_numeric_quo(VALUE x
, VALUE y
)
2034 if (RB_TYPE_P(x
, T_COMPLEX
)) {
2035 return rb_complex_div(x
, y
);
2038 if (RB_FLOAT_TYPE_P(y
)) {
2039 return rb_funcallv(x
, idFdiv
, 1, &y
);
2042 x
= rb_convert_type(x
, T_RATIONAL
, "Rational", "to_r");
2043 return rb_rational_div(x
, y
);
2047 rb_rational_canonicalize(VALUE x
)
2049 if (RB_TYPE_P(x
, T_RATIONAL
)) {
2051 if (f_one_p(dat
->den
)) return dat
->num
;
2058 * int.numerator -> self
2063 integer_numerator(VALUE self
)
2070 * int.denominator -> 1
2075 integer_denominator(VALUE self
)
2082 * flo.numerator -> integer
2084 * Returns the numerator. The result is machine dependent.
2086 * n = 0.3.numerator #=> 5404319552844595
2087 * d = 0.3.denominator #=> 18014398509481984
2090 * See also Float#denominator.
2093 rb_float_numerator(VALUE self
)
2095 double d
= RFLOAT_VALUE(self
);
2099 r
= float_to_r(self
);
2100 return nurat_numerator(r
);
2105 * flo.denominator -> integer
2107 * Returns the denominator (always positive). The result is machine
2110 * See also Float#numerator.
2113 rb_float_denominator(VALUE self
)
2115 double d
= RFLOAT_VALUE(self
);
2119 r
= float_to_r(self
);
2120 return nurat_denominator(r
);
2127 * Returns zero as a rational.
2130 nilclass_to_r(VALUE self
)
2132 return rb_rational_new1(INT2FIX(0));
2137 * nil.rationalize([eps]) -> (0/1)
2139 * Returns zero as a rational. The optional argument +eps+ is always
2143 nilclass_rationalize(int argc
, VALUE
*argv
, VALUE self
)
2145 rb_check_arity(argc
, 0, 1);
2146 return nilclass_to_r(self
);
2151 * int.to_r -> rational
2153 * Returns the value as a rational.
2156 * (1<<64).to_r #=> (18446744073709551616/1)
2159 integer_to_r(VALUE self
)
2161 return rb_rational_new1(self
);
2166 * int.rationalize([eps]) -> rational
2168 * Returns the value as a rational. The optional argument +eps+ is
2172 integer_rationalize(int argc
, VALUE
*argv
, VALUE self
)
2174 rb_check_arity(argc
, 0, 1);
2175 return integer_to_r(self
);
2179 float_decode_internal(VALUE self
, VALUE
*rf
, int *n
)
2183 f
= frexp(RFLOAT_VALUE(self
), n
);
2184 f
= ldexp(f
, DBL_MANT_DIG
);
2186 *rf
= rb_dbl2big(f
);
2191 * flt.to_r -> rational
2193 * Returns the value as a rational.
2195 * 2.0.to_r #=> (2/1)
2196 * 2.5.to_r #=> (5/2)
2197 * -0.75.to_r #=> (-3/4)
2198 * 0.0.to_r #=> (0/1)
2199 * 0.3.to_r #=> (5404319552844595/18014398509481984)
2201 * NOTE: 0.3.to_r isn't the same as "0.3".to_r. The latter is
2202 * equivalent to "3/10".to_r, but the former isn't so.
2204 * 0.3.to_r == 3/10r #=> false
2205 * "0.3".to_r == 3/10r #=> true
2207 * See also Float#rationalize.
2210 float_to_r(VALUE self
)
2215 float_decode_internal(self
, &f
, &n
);
2218 return rb_rational_new1(f
);
2220 return rb_rational_new1(rb_int_lshift(f
, INT2FIX(n
)));
2222 return rb_rational_new2(f
, rb_int_lshift(ONE
, INT2FIX(n
)));
2224 f
= rb_int_mul(f
, rb_int_pow(INT2FIX(FLT_RADIX
), n
));
2225 if (RB_TYPE_P(f
, T_RATIONAL
))
2227 return rb_rational_new1(f
);
2232 rb_flt_rationalize_with_prec(VALUE flt
, VALUE prec
)
2234 VALUE e
, a
, b
, p
, q
;
2241 return float_to_r(flt
);
2243 nurat_rationalize_internal(a
, b
, &p
, &q
);
2244 return rb_rational_new2(p
, q
);
2248 rb_flt_rationalize(VALUE flt
)
2250 VALUE a
, b
, f
, p
, q
, den
;
2253 float_decode_internal(flt
, &f
, &n
);
2254 if (INT_ZERO_P(f
) || n
>= 0)
2255 return rb_rational_new1(rb_int_lshift(f
, INT2FIX(n
)));
2258 VALUE radix_times_f
;
2260 radix_times_f
= rb_int_mul(INT2FIX(FLT_RADIX
), f
);
2261 #if FLT_RADIX == 2 && 0
2262 den
= rb_int_lshift(ONE
, INT2FIX(1-n
));
2264 den
= rb_int_positive_pow(FLT_RADIX
, 1-n
);
2267 a
= rb_int_minus(radix_times_f
, INT2FIX(FLT_RADIX
- 1));
2268 b
= rb_int_plus(radix_times_f
, INT2FIX(FLT_RADIX
- 1));
2272 return float_to_r(flt
);
2274 a
= rb_rational_new2(a
, den
);
2275 b
= rb_rational_new2(b
, den
);
2276 nurat_rationalize_internal(a
, b
, &p
, &q
);
2277 return rb_rational_new2(p
, q
);
2282 * flt.rationalize([eps]) -> rational
2284 * Returns a simpler approximation of the value (flt-|eps| <= result
2285 * <= flt+|eps|). If the optional argument +eps+ is not given,
2286 * it will be chosen automatically.
2288 * 0.3.rationalize #=> (3/10)
2289 * 1.333.rationalize #=> (1333/1000)
2290 * 1.333.rationalize(0.01) #=> (4/3)
2292 * See also Float#to_r.
2295 float_rationalize(int argc
, VALUE
*argv
, VALUE self
)
2297 double d
= RFLOAT_VALUE(self
);
2300 if (neg
) self
= DBL2NUM(-d
);
2302 if (rb_check_arity(argc
, 0, 1)) {
2303 rat
= rb_flt_rationalize_with_prec(self
, argv
[0]);
2306 rat
= rb_flt_rationalize(self
);
2308 if (neg
) RATIONAL_SET_NUM(rat
, rb_int_uminus(RRATIONAL(rat
)->num
));
2315 return (c
== '-' || c
== '+');
2319 read_sign(const char **s
, const char *const e
)
2323 if (*s
< e
&& issign(**s
)) {
2333 return (c
== 'e' || c
== 'E');
2337 negate_num(VALUE num
)
2339 if (FIXNUM_P(num
)) {
2340 return rb_int_uminus(num
);
2344 return rb_big_norm(num
);
2349 read_num(const char **s
, const char *const end
, VALUE
*num
, VALUE
*nexp
)
2351 VALUE fp
= ONE
, exp
, fn
= ZERO
, n
= ZERO
;
2352 int expsign
= 0, ok
= 0;
2357 if (*s
< end
&& **s
!= '.') {
2358 n
= rb_int_parse_cstr(*s
, end
-*s
, &e
, NULL
,
2359 10, RB_INT_PARSE_UNDERSCORE
);
2367 if (*s
< end
&& **s
== '.') {
2371 fp
= rb_int_parse_cstr(*s
, end
-*s
, &e
, &count
,
2372 10, RB_INT_PARSE_UNDERSCORE
);
2377 VALUE l
= f_expt10(*nexp
= SIZET2NUM(count
));
2378 n
= n
== ZERO
? fp
: rb_int_plus(rb_int_mul(*num
, l
), fp
);
2380 fn
= SIZET2NUM(count
);
2385 if (ok
&& *s
+ 1 < end
&& islettere(**s
)) {
2387 expsign
= read_sign(s
, end
);
2388 exp
= rb_int_parse_cstr(*s
, end
-*s
, &e
, NULL
,
2389 10, RB_INT_PARSE_UNDERSCORE
);
2394 if (expsign
== '-') {
2395 if (fn
!= ZERO
) exp
= rb_int_plus(exp
, fn
);
2398 if (fn
!= ZERO
) exp
= rb_int_minus(exp
, fn
);
2399 exp
= negate_num(exp
);
2408 inline static const char *
2409 skip_ws(const char *s
, const char *e
)
2411 while (s
< e
&& isspace((unsigned char)*s
))
2417 parse_rat(const char *s
, const char *const e
, int strict
, int raise
)
2420 VALUE num
, den
, nexp
, dexp
;
2423 sign
= read_sign(&s
, e
);
2425 if (!read_num(&s
, e
, &num
, &nexp
)) {
2426 if (strict
) return Qnil
;
2427 return nurat_s_alloc(rb_cRational
);
2430 if (s
< e
&& *s
== '/') {
2432 if (!read_num(&s
, e
, &den
, &dexp
)) {
2433 if (strict
) return Qnil
;
2436 else if (den
== ZERO
) {
2437 if (!raise
) return Qnil
;
2440 else if (strict
&& skip_ws(s
, e
) != e
) {
2444 nexp
= rb_int_minus(nexp
, dexp
);
2445 nurat_reduce(&num
, &den
);
2448 else if (strict
&& skip_ws(s
, e
) != e
) {
2453 if (INT_NEGATIVE_P(nexp
)) {
2455 if (FIXNUM_P(nexp
)) {
2456 mul
= f_expt10(LONG2NUM(-FIX2LONG(nexp
)));
2457 if (! RB_FLOAT_TYPE_P(mul
)) {
2458 num
= rb_int_mul(num
, mul
);
2462 return sign
== '-' ? DBL2NUM(-HUGE_VAL
) : DBL2NUM(HUGE_VAL
);
2466 if (FIXNUM_P(nexp
)) {
2467 div
= f_expt10(nexp
);
2468 if (! RB_FLOAT_TYPE_P(div
)) {
2469 den
= rb_int_mul(den
, div
);
2473 return sign
== '-' ? DBL2NUM(-0.0) : DBL2NUM(+0.0);
2476 nurat_reduce(&num
, &den
);
2480 num
= negate_num(num
);
2483 return rb_rational_raw(num
, den
);
2487 string_to_r_strict(VALUE self
, int raise
)
2491 rb_must_asciicompat(self
);
2493 num
= parse_rat(RSTRING_PTR(self
), RSTRING_END(self
), 1, raise
);
2495 if (!raise
) return Qnil
;
2496 rb_raise(rb_eArgError
, "invalid value for convert(): %+"PRIsVALUE
,
2500 if (RB_FLOAT_TYPE_P(num
) && !FLOAT_ZERO_P(num
)) {
2501 if (!raise
) return Qnil
;
2502 rb_raise(rb_eFloatDomainError
, "Infinity");
2509 * str.to_r -> rational
2511 * Returns the result of interpreting leading characters in +str+
2512 * as a rational. Leading whitespace and extraneous characters
2513 * past the end of a valid number are ignored.
2514 * Digit sequences can be separated by an underscore.
2515 * If there is not a valid number at the start of +str+,
2516 * zero is returned. This method never raises an exception.
2518 * ' 2 '.to_r #=> (2/1)
2519 * '300/2'.to_r #=> (150/1)
2520 * '-9.2'.to_r #=> (-46/5)
2521 * '-9.2e2'.to_r #=> (-920/1)
2522 * '1_234_567'.to_r #=> (1234567/1)
2523 * '21 June 09'.to_r #=> (21/1)
2524 * '21/06/09'.to_r #=> (7/2)
2525 * 'BWV 1079'.to_r #=> (0/1)
2527 * NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is
2528 * equivalent to "3/10".to_r, but the latter isn't so.
2530 * "0.3".to_r == 3/10r #=> true
2531 * 0.3.to_r == 3/10r #=> false
2533 * See also Kernel#Rational.
2536 string_to_r(VALUE self
)
2540 rb_must_asciicompat(self
);
2542 num
= parse_rat(RSTRING_PTR(self
), RSTRING_END(self
), 0, TRUE
);
2544 if (RB_FLOAT_TYPE_P(num
) && !FLOAT_ZERO_P(num
))
2545 rb_raise(rb_eFloatDomainError
, "Infinity");
2550 rb_cstr_to_rat(const char *s
, int strict
) /* for complex's internal */
2554 num
= parse_rat(s
, s
+ strlen(s
), strict
, TRUE
);
2556 if (RB_FLOAT_TYPE_P(num
) && !FLOAT_ZERO_P(num
))
2557 rb_raise(rb_eFloatDomainError
, "Infinity");
2562 to_rational(VALUE val
)
2564 return rb_convert_type_with_id(val
, T_RATIONAL
, "Rational", idTo_r
);
2568 nurat_convert(VALUE klass
, VALUE numv
, VALUE denv
, int raise
)
2570 VALUE a1
= numv
, a2
= denv
;
2573 assert(a1
!= Qundef
);
2575 if (NIL_P(a1
) || NIL_P(a2
)) {
2576 if (!raise
) return Qnil
;
2577 rb_raise(rb_eTypeError
, "can't convert nil into Rational");
2580 if (RB_TYPE_P(a1
, T_COMPLEX
)) {
2581 if (k_exact_zero_p(RCOMPLEX(a1
)->imag
))
2582 a1
= RCOMPLEX(a1
)->real
;
2585 if (RB_TYPE_P(a2
, T_COMPLEX
)) {
2586 if (k_exact_zero_p(RCOMPLEX(a2
)->imag
))
2587 a2
= RCOMPLEX(a2
)->real
;
2590 if (RB_INTEGER_TYPE_P(a1
)) {
2593 else if (RB_FLOAT_TYPE_P(a1
)) {
2594 a1
= float_to_r(a1
);
2596 else if (RB_TYPE_P(a1
, T_RATIONAL
)) {
2599 else if (RB_TYPE_P(a1
, T_STRING
)) {
2600 a1
= string_to_r_strict(a1
, raise
);
2601 if (!raise
&& NIL_P(a1
)) return Qnil
;
2603 else if (!rb_respond_to(a1
, idTo_r
)) {
2604 VALUE tmp
= rb_protect(rb_check_to_int
, a1
, NULL
);
2605 rb_set_errinfo(Qnil
);
2611 if (RB_INTEGER_TYPE_P(a2
)) {
2614 else if (RB_FLOAT_TYPE_P(a2
)) {
2615 a2
= float_to_r(a2
);
2617 else if (RB_TYPE_P(a2
, T_RATIONAL
)) {
2620 else if (RB_TYPE_P(a2
, T_STRING
)) {
2621 a2
= string_to_r_strict(a2
, raise
);
2622 if (!raise
&& NIL_P(a2
)) return Qnil
;
2624 else if (a2
!= Qundef
&& !rb_respond_to(a2
, idTo_r
)) {
2625 VALUE tmp
= rb_protect(rb_check_to_int
, a2
, NULL
);
2626 rb_set_errinfo(Qnil
);
2632 if (RB_TYPE_P(a1
, T_RATIONAL
)) {
2633 if (a2
== Qundef
|| (k_exact_one_p(a2
)))
2638 if (!RB_INTEGER_TYPE_P(a1
)) {
2640 VALUE result
= rb_protect(to_rational
, a1
, NULL
);
2641 rb_set_errinfo(Qnil
);
2644 return to_rational(a1
);
2648 if (!k_numeric_p(a1
)) {
2650 a1
= rb_protect(to_rational
, a1
, &state
);
2652 rb_set_errinfo(Qnil
);
2657 a1
= rb_check_convert_type_with_id(a1
, T_RATIONAL
, "Rational", idTo_r
);
2660 if (!k_numeric_p(a2
)) {
2662 a2
= rb_protect(to_rational
, a2
, &state
);
2664 rb_set_errinfo(Qnil
);
2669 a2
= rb_check_convert_type_with_id(a2
, T_RATIONAL
, "Rational", idTo_r
);
2672 if ((k_numeric_p(a1
) && k_numeric_p(a2
)) &&
2673 (!f_integer_p(a1
) || !f_integer_p(a2
))) {
2674 VALUE tmp
= rb_protect(to_rational
, a1
, &state
);
2679 rb_set_errinfo(Qnil
);
2681 return f_div(a1
, a2
);
2685 a1
= nurat_int_value(a1
);
2690 else if (!k_integer_p(a2
) && !raise
) {
2694 a2
= nurat_int_value(a2
);
2698 return nurat_s_canonicalize_internal(klass
, a1
, a2
);
2702 nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
)
2706 if (rb_scan_args(argc
, argv
, "11", &a1
, &a2
) == 1) {
2710 return nurat_convert(klass
, a1
, a2
, TRUE
);
2714 * A rational number can be represented as a pair of integer numbers:
2715 * a/b (b>0), where a is the numerator and b is the denominator.
2716 * Integer a equals rational a/1 mathematically.
2718 * You can create a \Rational object explicitly with:
2720 * - A {rational literal}[doc/syntax/literals_rdoc.html#label-Rational+Literals].
2722 * You can convert certain objects to Rationals with:
2724 * - \Method {Rational}[Kernel.html#method-i-Rational].
2728 * Rational(1) #=> (1/1)
2729 * Rational(2, 3) #=> (2/3)
2730 * Rational(4, -6) #=> (-2/3) # Reduced.
2734 * You can also create rational objects from floating-point numbers or
2737 * Rational(0.3) #=> (5404319552844595/18014398509481984)
2738 * Rational('0.3') #=> (3/10)
2739 * Rational('2/3') #=> (2/3)
2741 * 0.3.to_r #=> (5404319552844595/18014398509481984)
2742 * '0.3'.to_r #=> (3/10)
2743 * '2/3'.to_r #=> (2/3)
2744 * 0.3.rationalize #=> (3/10)
2746 * A rational object is an exact number, which helps you to write
2747 * programs without any rounding errors.
2749 * 10.times.inject(0) {|t| t + 0.1 } #=> 0.9999999999999999
2750 * 10.times.inject(0) {|t| t + Rational('0.1') } #=> (1/1)
2752 * However, when an expression includes an inexact component (numerical value
2753 * or operation), it will produce an inexact result.
2755 * Rational(10) / 3 #=> (10/3)
2756 * Rational(10) / 3.0 #=> 3.3333333333333335
2758 * Rational(-8) ** Rational(1, 3)
2759 * #=> (1.0000000000000002+1.7320508075688772i)
2765 id_abs
= rb_intern_const("abs");
2766 id_integer_p
= rb_intern_const("integer?");
2767 id_i_num
= rb_intern_const("@numerator");
2768 id_i_den
= rb_intern_const("@denominator");
2770 rb_cRational
= rb_define_class("Rational", rb_cNumeric
);
2772 rb_define_alloc_func(rb_cRational
, nurat_s_alloc
);
2773 rb_undef_method(CLASS_OF(rb_cRational
), "allocate");
2775 rb_undef_method(CLASS_OF(rb_cRational
), "new");
2777 rb_define_global_function("Rational", nurat_f_rational
, -1);
2779 rb_define_method(rb_cRational
, "numerator", nurat_numerator
, 0);
2780 rb_define_method(rb_cRational
, "denominator", nurat_denominator
, 0);
2782 rb_define_method(rb_cRational
, "-@", rb_rational_uminus
, 0);
2783 rb_define_method(rb_cRational
, "+", rb_rational_plus
, 1);
2784 rb_define_method(rb_cRational
, "-", rb_rational_minus
, 1);
2785 rb_define_method(rb_cRational
, "*", rb_rational_mul
, 1);
2786 rb_define_method(rb_cRational
, "/", rb_rational_div
, 1);
2787 rb_define_method(rb_cRational
, "quo", rb_rational_div
, 1);
2788 rb_define_method(rb_cRational
, "fdiv", nurat_fdiv
, 1);
2789 rb_define_method(rb_cRational
, "**", nurat_expt
, 1);
2791 rb_define_method(rb_cRational
, "<=>", rb_rational_cmp
, 1);
2792 rb_define_method(rb_cRational
, "==", nurat_eqeq_p
, 1);
2793 rb_define_method(rb_cRational
, "coerce", nurat_coerce
, 1);
2795 rb_define_method(rb_cRational
, "positive?", nurat_positive_p
, 0);
2796 rb_define_method(rb_cRational
, "negative?", nurat_negative_p
, 0);
2797 rb_define_method(rb_cRational
, "abs", rb_rational_abs
, 0);
2798 rb_define_method(rb_cRational
, "magnitude", rb_rational_abs
, 0);
2800 rb_define_method(rb_cRational
, "floor", nurat_floor_n
, -1);
2801 rb_define_method(rb_cRational
, "ceil", nurat_ceil_n
, -1);
2802 rb_define_method(rb_cRational
, "truncate", nurat_truncate_n
, -1);
2803 rb_define_method(rb_cRational
, "round", nurat_round_n
, -1);
2805 rb_define_method(rb_cRational
, "to_i", nurat_truncate
, 0);
2806 rb_define_method(rb_cRational
, "to_f", nurat_to_f
, 0);
2807 rb_define_method(rb_cRational
, "to_r", nurat_to_r
, 0);
2808 rb_define_method(rb_cRational
, "rationalize", nurat_rationalize
, -1);
2810 rb_define_method(rb_cRational
, "hash", nurat_hash
, 0);
2812 rb_define_method(rb_cRational
, "to_s", nurat_to_s
, 0);
2813 rb_define_method(rb_cRational
, "inspect", nurat_inspect
, 0);
2815 rb_define_private_method(rb_cRational
, "marshal_dump", nurat_marshal_dump
, 0);
2817 compat
= rb_define_class_under(rb_cRational
, "compatible", rb_cObject
);
2818 rb_define_private_method(compat
, "marshal_load", nurat_marshal_load
, 1);
2819 rb_marshal_define_compat(rb_cRational
, compat
, nurat_dumper
, nurat_loader
);
2821 rb_define_method(rb_cInteger
, "gcd", rb_gcd
, 1);
2822 rb_define_method(rb_cInteger
, "lcm", rb_lcm
, 1);
2823 rb_define_method(rb_cInteger
, "gcdlcm", rb_gcdlcm
, 1);
2825 rb_define_method(rb_cNumeric
, "numerator", numeric_numerator
, 0);
2826 rb_define_method(rb_cNumeric
, "denominator", numeric_denominator
, 0);
2827 rb_define_method(rb_cNumeric
, "quo", rb_numeric_quo
, 1);
2829 rb_define_method(rb_cInteger
, "numerator", integer_numerator
, 0);
2830 rb_define_method(rb_cInteger
, "denominator", integer_denominator
, 0);
2832 rb_define_method(rb_cFloat
, "numerator", rb_float_numerator
, 0);
2833 rb_define_method(rb_cFloat
, "denominator", rb_float_denominator
, 0);
2835 rb_define_method(rb_cNilClass
, "to_r", nilclass_to_r
, 0);
2836 rb_define_method(rb_cNilClass
, "rationalize", nilclass_rationalize
, -1);
2837 rb_define_method(rb_cInteger
, "to_r", integer_to_r
, 0);
2838 rb_define_method(rb_cInteger
, "rationalize", integer_rationalize
, -1);
2839 rb_define_method(rb_cFloat
, "to_r", float_to_r
, 0);
2840 rb_define_method(rb_cFloat
, "rationalize", float_rationalize
, -1);
2842 rb_define_method(rb_cString
, "to_r", string_to_r
, 0);
2844 rb_define_private_method(CLASS_OF(rb_cRational
), "convert", nurat_s_convert
, -1);
2846 rb_provide("rational.so"); /* for backward compatibility */