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"
19 #if defined(HAVE_LIBGMP) && defined(HAVE_GMP_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"
39 #define ZERO INT2FIX(0)
40 #define ONE INT2FIX(1)
41 #define TWO INT2FIX(2)
43 #define GMP_GCD_DIGITS 1
45 #define INT_ZERO_P(x) (FIXNUM_P(x) ? FIXNUM_ZERO_P(x) : rb_bigzero_p(x))
49 static ID id_abs
, id_integer_p
,
53 #define id_to_i idTo_i
55 #define f_inspect rb_inspect
56 #define f_to_s rb_obj_as_string
58 static VALUE
nurat_to_f(VALUE self
);
59 static VALUE
float_to_r(VALUE self
);
62 f_add(VALUE x
, VALUE y
)
68 if (RB_INTEGER_TYPE_P(x
))
69 return rb_int_plus(x
, y
);
70 return rb_funcall(x
, '+', 1, y
);
74 f_div(VALUE x
, VALUE y
)
78 if (RB_INTEGER_TYPE_P(x
))
79 return rb_int_div(x
, y
);
80 return rb_funcall(x
, '/', 1, y
);
84 f_lt_p(VALUE x
, VALUE y
)
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
);
92 return RTEST(rb_funcall(x
, '<', 1, y
));
96 /* f_mod is used only in f_gcd defined when NDEBUG is not defined */
98 f_mod(VALUE x
, VALUE y
)
100 if (RB_INTEGER_TYPE_P(x
))
101 return rb_int_modulo(x
, y
);
102 return rb_funcall(x
, '%', 1, y
);
107 f_mul(VALUE x
, VALUE y
)
109 if (FIXNUM_ZERO_P(y
) && RB_INTEGER_TYPE_P(x
))
111 if (y
== ONE
) return x
;
112 if (FIXNUM_ZERO_P(x
) && RB_INTEGER_TYPE_P(y
))
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
);
121 f_sub(VALUE x
, VALUE y
)
123 if (FIXNUM_P(y
) && FIXNUM_ZERO_P(y
))
125 return rb_funcall(x
, '-', 1, y
);
131 if (RB_INTEGER_TYPE_P(x
))
132 return rb_int_abs(x
);
133 return rb_funcall(x
, id_abs
, 0);
140 return RB_INTEGER_TYPE_P(x
);
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);
152 f_eqeq_p(VALUE x
, VALUE y
)
154 if (FIXNUM_P(x
) && FIXNUM_P(y
))
156 if (RB_INTEGER_TYPE_P(x
))
157 return RTEST(rb_int_equal(x
, y
));
158 return (int)rb_equal(x
, y
);
162 f_idiv(VALUE x
, VALUE y
)
164 if (RB_INTEGER_TYPE_P(x
))
165 return rb_int_idiv(x
, y
);
166 return rb_funcall(x
, id_idiv
, 1, y
);
169 #define f_expt10(x) rb_int_pow(INT2FIX(10), x)
174 if (RB_INTEGER_TYPE_P(x
)) {
175 return FIXNUM_ZERO_P(x
);
177 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
178 VALUE num
= RRATIONAL(x
)->num
;
180 return FIXNUM_ZERO_P(num
);
182 return (int)rb_equal(x
, ZERO
);
185 #define f_nonzero_p(x) (!f_zero_p(x))
190 if (RB_INTEGER_TYPE_P(x
)) {
191 return x
== LONG2FIX(1);
193 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
194 VALUE num
= RRATIONAL(x
)->num
;
195 VALUE den
= RRATIONAL(x
)->den
;
197 return num
== LONG2FIX(1) && den
== LONG2FIX(1);
199 return (int)rb_equal(x
, ONE
);
203 f_minus_one_p(VALUE x
)
205 if (RB_INTEGER_TYPE_P(x
)) {
206 return x
== LONG2FIX(-1);
208 else if (RB_BIGNUM_TYPE_P(x
)) {
211 else if (RB_TYPE_P(x
, T_RATIONAL
)) {
212 VALUE num
= RRATIONAL(x
)->num
;
213 VALUE den
= RRATIONAL(x
)->den
;
215 return num
== LONG2FIX(-1) && den
== LONG2FIX(1);
217 return (int)rb_equal(x
, INT2FIX(-1));
221 f_kind_of_p(VALUE x
, VALUE c
)
223 return (int)rb_obj_is_kind_of(x
, c
);
229 return f_kind_of_p(x
, rb_cNumeric
);
235 return RB_INTEGER_TYPE_P(x
);
241 return RB_FLOAT_TYPE_P(x
);
245 k_rational_p(VALUE x
)
247 return RB_TYPE_P(x
, T_RATIONAL
);
250 #define k_exact_p(x) (!k_float_p(x))
251 #define k_inexact_p(x) k_float_p(x)
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))
258 rb_gcd_gmp(VALUE x
, VALUE y
)
260 const size_t nails
= (sizeof(BDIGIT
)-SIZEOF_BDIGIT
)*CHAR_BIT
;
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
));
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
);
283 return rb_big_norm(z
);
288 #define f_gcd f_gcd_orig
292 i_gcd(long x
, long y
)
294 unsigned long u
, v
, t
;
307 u
= (unsigned long)x
;
308 v
= (unsigned long)y
;
309 for (shift
= 0; ((u
| v
) & 1) == 0; ++shift
) {
329 return (long)(u
<< shift
);
333 f_gcd_normal(VALUE x
, VALUE y
)
337 if (FIXNUM_P(x
) && FIXNUM_P(y
))
338 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
340 if (INT_NEGATIVE_P(x
))
341 x
= rb_int_uminus(x
);
342 if (INT_NEGATIVE_P(y
))
343 y
= rb_int_uminus(y
);
352 if (FIXNUM_ZERO_P(x
))
355 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
358 x
= rb_int_modulo(y
, x
);
365 rb_gcd_normal(VALUE x
, VALUE y
)
367 return f_gcd_normal(x
, y
);
371 f_gcd(VALUE x
, VALUE y
)
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
);
381 return f_gcd_normal(x
, y
);
388 f_gcd(VALUE x
, VALUE y
)
390 VALUE r
= f_gcd_orig(x
, y
);
391 if (f_nonzero_p(r
)) {
392 RUBY_ASSERT(f_zero_p(f_mod(x
, r
)));
393 RUBY_ASSERT(f_zero_p(f_mod(y
, r
)));
400 f_lcm(VALUE x
, VALUE y
)
402 if (INT_ZERO_P(x
) || INT_ZERO_P(y
))
404 return f_abs(f_mul(f_div(x
, f_gcd(x
, y
)), y
));
407 #define get_dat1(x) \
408 struct RRational *dat = RRATIONAL(x)
410 #define get_dat2(x,y) \
411 struct RRational *adat = RRATIONAL(x), *bdat = RRATIONAL(y)
414 nurat_s_new_internal(VALUE klass
, VALUE num
, VALUE den
)
416 NEWOBJ_OF(obj
, struct RRational
, klass
, T_RATIONAL
| (RGENGC_WB_PROTECTED_RATIONAL
? FL_WB_PROTECTED
: 0),
417 sizeof(struct RRational
), 0);
419 RATIONAL_SET_NUM((VALUE
)obj
, num
);
420 RATIONAL_SET_DEN((VALUE
)obj
, den
);
421 OBJ_FREEZE((VALUE
)obj
);
427 nurat_s_alloc(VALUE klass
)
429 return nurat_s_new_internal(klass
, ZERO
, ONE
);
433 f_rational_new_bang1(VALUE klass
, VALUE x
)
435 return nurat_s_new_internal(klass
, x
, ONE
);
439 nurat_int_check(VALUE num
)
441 if (!RB_INTEGER_TYPE_P(num
)) {
442 if (!k_numeric_p(num
) || !f_integer_p(num
))
443 rb_raise(rb_eTypeError
, "not an integer");
448 nurat_int_value(VALUE num
)
450 nurat_int_check(num
);
451 if (!k_integer_p(num
))
457 nurat_canonicalize(VALUE
*num
, VALUE
*den
)
459 RUBY_ASSERT(num
); RUBY_ASSERT(RB_INTEGER_TYPE_P(*num
));
460 RUBY_ASSERT(den
); RUBY_ASSERT(RB_INTEGER_TYPE_P(*den
));
461 if (INT_NEGATIVE_P(*den
)) {
462 *num
= rb_int_uminus(*num
);
463 *den
= rb_int_uminus(*den
);
465 else if (INT_ZERO_P(*den
)) {
471 nurat_reduce(VALUE
*x
, VALUE
*y
)
474 if (*x
== ONE
|| *y
== ONE
) return;
476 *x
= f_idiv(*x
, gcd
);
477 *y
= f_idiv(*y
, gcd
);
481 nurat_s_canonicalize_internal(VALUE klass
, VALUE num
, VALUE den
)
483 nurat_canonicalize(&num
, &den
);
484 nurat_reduce(&num
, &den
);
486 return nurat_s_new_internal(klass
, num
, den
);
490 nurat_s_canonicalize_internal_no_reduce(VALUE klass
, VALUE num
, VALUE den
)
492 nurat_canonicalize(&num
, &den
);
494 return nurat_s_new_internal(klass
, num
, den
);
498 f_rational_new2(VALUE klass
, VALUE x
, VALUE y
)
500 RUBY_ASSERT(!k_rational_p(x
));
501 RUBY_ASSERT(!k_rational_p(y
));
502 return nurat_s_canonicalize_internal(klass
, x
, y
);
506 f_rational_new_no_reduce2(VALUE klass
, VALUE x
, VALUE y
)
508 RUBY_ASSERT(!k_rational_p(x
));
509 RUBY_ASSERT(!k_rational_p(y
));
510 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, y
);
513 static VALUE
nurat_convert(VALUE klass
, VALUE numv
, VALUE denv
, int raise
);
514 static VALUE
nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
);
518 * Rational(x, y, exception: true) -> rational or nil
519 * Rational(arg, exception: true) -> rational or nil
521 * Returns +x/y+ or +arg+ as a Rational.
523 * Rational(2, 3) #=> (2/3)
524 * Rational(5) #=> (5/1)
525 * Rational(0.5) #=> (1/2)
526 * Rational(0.3) #=> (5404319552844595/18014398509481984)
528 * Rational("2/3") #=> (2/3)
529 * Rational("0.3") #=> (3/10)
531 * Rational("10 cents") #=> ArgumentError
532 * Rational(nil) #=> TypeError
533 * Rational(1, nil) #=> TypeError
535 * Rational("10 cents", exception: false) #=> nil
537 * Syntax of the string form:
539 * string form = extra spaces , rational , extra spaces ;
540 * rational = [ sign ] , unsigned rational ;
541 * unsigned rational = numerator | numerator , "/" , denominator ;
542 * numerator = integer part | fractional part | integer part , fractional part ;
543 * denominator = digits ;
544 * integer part = digits ;
545 * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
547 * digits = digit , { digit | "_" , digit } ;
548 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
549 * extra spaces = ? \s* ? ;
551 * See also String#to_r.
554 nurat_f_rational(int argc
, VALUE
*argv
, VALUE klass
)
556 VALUE a1
, a2
, opts
= Qnil
;
559 if (rb_scan_args(argc
, argv
, "11:", &a1
, &a2
, &opts
) == 1) {
563 raise
= rb_opts_exception_p(opts
, raise
);
565 return nurat_convert(rb_cRational
, a1
, a2
, raise
);
570 * rat.numerator -> integer
572 * Returns the numerator.
574 * Rational(7).numerator #=> 7
575 * Rational(7, 1).numerator #=> 7
576 * Rational(9, -4).numerator #=> -9
577 * Rational(-2, -10).numerator #=> 1
580 nurat_numerator(VALUE self
)
588 * rat.denominator -> integer
590 * Returns the denominator (always positive).
592 * Rational(7).denominator #=> 1
593 * Rational(7, 1).denominator #=> 1
594 * Rational(9, -4).denominator #=> 4
595 * Rational(-2, -10).denominator #=> 5
598 nurat_denominator(VALUE self
)
611 rb_rational_uminus(VALUE self
)
613 const int unused
= (RUBY_ASSERT(RB_TYPE_P(self
, T_RATIONAL
)), 0);
616 return f_rational_new2(CLASS_OF(self
), rb_int_uminus(dat
->num
), dat
->den
);
620 #define f_imul f_imul_orig
624 f_imul(long a
, long b
)
628 if (a
== 0 || b
== 0)
635 if (MUL_OVERFLOW_LONG_P(a
, b
))
636 r
= rb_big_mul(rb_int2big(a
), rb_int2big(b
));
646 f_imul(long x
, long y
)
648 VALUE r
= f_imul_orig(x
, y
);
649 RUBY_ASSERT(f_eqeq_p(r
, f_mul(LONG2NUM(x
), LONG2NUM(y
))));
655 f_addsub(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
659 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
660 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
661 long an
= FIX2LONG(anum
);
662 long ad
= FIX2LONG(aden
);
663 long bn
= FIX2LONG(bnum
);
664 long bd
= FIX2LONG(bden
);
665 long ig
= i_gcd(ad
, bd
);
667 VALUE g
= LONG2NUM(ig
);
668 VALUE a
= f_imul(an
, bd
/ ig
);
669 VALUE b
= f_imul(bn
, ad
/ ig
);
673 c
= rb_int_plus(a
, b
);
675 c
= rb_int_minus(a
, b
);
677 b
= rb_int_idiv(aden
, g
);
679 num
= rb_int_idiv(c
, g
);
680 a
= rb_int_idiv(bden
, g
);
681 den
= rb_int_mul(a
, b
);
683 else if (RB_INTEGER_TYPE_P(anum
) && RB_INTEGER_TYPE_P(aden
) &&
684 RB_INTEGER_TYPE_P(bnum
) && RB_INTEGER_TYPE_P(bden
)) {
685 VALUE g
= f_gcd(aden
, bden
);
686 VALUE a
= rb_int_mul(anum
, rb_int_idiv(bden
, g
));
687 VALUE b
= rb_int_mul(bnum
, rb_int_idiv(aden
, g
));
691 c
= rb_int_plus(a
, b
);
693 c
= rb_int_minus(a
, b
);
695 b
= rb_int_idiv(aden
, g
);
697 num
= rb_int_idiv(c
, g
);
698 a
= rb_int_idiv(bden
, g
);
699 den
= rb_int_mul(a
, b
);
702 double a
= NUM2DBL(anum
) / NUM2DBL(aden
);
703 double b
= NUM2DBL(bnum
) / NUM2DBL(bden
);
704 double c
= k
== '+' ? a
+ b
: a
- b
;
707 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
710 static double nurat_to_double(VALUE self
);
713 * rat + numeric -> numeric
717 * Rational(2, 3) + Rational(2, 3) #=> (4/3)
718 * Rational(900) + Rational(1) #=> (901/1)
719 * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18)
720 * Rational(9, 8) + 4 #=> (41/8)
721 * Rational(20, 9) + 9.8 #=> 12.022222222222222
724 rb_rational_plus(VALUE self
, VALUE other
)
726 if (RB_INTEGER_TYPE_P(other
)) {
730 return f_rational_new_no_reduce2(CLASS_OF(self
),
731 rb_int_plus(dat
->num
, rb_int_mul(other
, dat
->den
)),
735 else if (RB_FLOAT_TYPE_P(other
)) {
736 return DBL2NUM(nurat_to_double(self
) + RFLOAT_VALUE(other
));
738 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
740 get_dat2(self
, other
);
742 return f_addsub(self
,
743 adat
->num
, adat
->den
,
744 bdat
->num
, bdat
->den
, '+');
748 return rb_num_coerce_bin(self
, other
, '+');
754 * rat - numeric -> numeric
756 * Performs subtraction.
758 * Rational(2, 3) - Rational(2, 3) #=> (0/1)
759 * Rational(900) - Rational(1) #=> (899/1)
760 * Rational(-2, 9) - Rational(-9, 2) #=> (77/18)
761 * Rational(9, 8) - 4 #=> (-23/8)
762 * Rational(20, 9) - 9.8 #=> -7.577777777777778
765 rb_rational_minus(VALUE self
, VALUE other
)
767 if (RB_INTEGER_TYPE_P(other
)) {
771 return f_rational_new_no_reduce2(CLASS_OF(self
),
772 rb_int_minus(dat
->num
, rb_int_mul(other
, dat
->den
)),
776 else if (RB_FLOAT_TYPE_P(other
)) {
777 return DBL2NUM(nurat_to_double(self
) - RFLOAT_VALUE(other
));
779 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
781 get_dat2(self
, other
);
783 return f_addsub(self
,
784 adat
->num
, adat
->den
,
785 bdat
->num
, bdat
->den
, '-');
789 return rb_num_coerce_bin(self
, other
, '-');
794 f_muldiv(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
798 RUBY_ASSERT(RB_TYPE_P(self
, T_RATIONAL
));
800 /* Integer#** can return Rational with Float right now */
801 if (RB_FLOAT_TYPE_P(anum
) || RB_FLOAT_TYPE_P(aden
) ||
802 RB_FLOAT_TYPE_P(bnum
) || RB_FLOAT_TYPE_P(bden
)) {
803 double an
= NUM2DBL(anum
), ad
= NUM2DBL(aden
);
804 double bn
= NUM2DBL(bnum
), bd
= NUM2DBL(bden
);
805 double x
= (an
* bn
) / (ad
* bd
);
809 RUBY_ASSERT(RB_INTEGER_TYPE_P(anum
));
810 RUBY_ASSERT(RB_INTEGER_TYPE_P(aden
));
811 RUBY_ASSERT(RB_INTEGER_TYPE_P(bnum
));
812 RUBY_ASSERT(RB_INTEGER_TYPE_P(bden
));
817 if (INT_NEGATIVE_P(bnum
)) {
818 anum
= rb_int_uminus(anum
);
819 bnum
= rb_int_uminus(bnum
);
826 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
827 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
828 long an
= FIX2LONG(anum
);
829 long ad
= FIX2LONG(aden
);
830 long bn
= FIX2LONG(bnum
);
831 long bd
= FIX2LONG(bden
);
832 long g1
= i_gcd(an
, bd
);
833 long g2
= i_gcd(ad
, bn
);
835 num
= f_imul(an
/ g1
, bn
/ g2
);
836 den
= f_imul(ad
/ g2
, bd
/ g1
);
839 VALUE g1
= f_gcd(anum
, bden
);
840 VALUE g2
= f_gcd(aden
, bnum
);
842 num
= rb_int_mul(rb_int_idiv(anum
, g1
), rb_int_idiv(bnum
, g2
));
843 den
= rb_int_mul(rb_int_idiv(aden
, g2
), rb_int_idiv(bden
, g1
));
845 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
850 * rat * numeric -> numeric
852 * Performs multiplication.
854 * Rational(2, 3) * Rational(2, 3) #=> (4/9)
855 * Rational(900) * Rational(1) #=> (900/1)
856 * Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
857 * Rational(9, 8) * 4 #=> (9/2)
858 * Rational(20, 9) * 9.8 #=> 21.77777777777778
861 rb_rational_mul(VALUE self
, VALUE other
)
863 if (RB_INTEGER_TYPE_P(other
)) {
867 return f_muldiv(self
,
872 else if (RB_FLOAT_TYPE_P(other
)) {
873 return DBL2NUM(nurat_to_double(self
) * RFLOAT_VALUE(other
));
875 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
877 get_dat2(self
, other
);
879 return f_muldiv(self
,
880 adat
->num
, adat
->den
,
881 bdat
->num
, bdat
->den
, '*');
885 return rb_num_coerce_bin(self
, other
, '*');
891 * rat / numeric -> numeric
892 * rat.quo(numeric) -> numeric
896 * Rational(2, 3) / Rational(2, 3) #=> (1/1)
897 * Rational(900) / Rational(1) #=> (900/1)
898 * Rational(-2, 9) / Rational(-9, 2) #=> (4/81)
899 * Rational(9, 8) / 4 #=> (9/32)
900 * Rational(20, 9) / 9.8 #=> 0.22675736961451246
903 rb_rational_div(VALUE self
, VALUE other
)
905 if (RB_INTEGER_TYPE_P(other
)) {
911 return f_muldiv(self
,
916 else if (RB_FLOAT_TYPE_P(other
)) {
917 VALUE v
= nurat_to_f(self
);
918 return rb_flo_div_flo(v
, other
);
920 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
924 get_dat2(self
, other
);
927 return f_rational_new_no_reduce2(CLASS_OF(self
),
928 bdat
->den
, bdat
->num
);
930 return f_muldiv(self
,
931 adat
->num
, adat
->den
,
932 bdat
->num
, bdat
->den
, '/');
936 return rb_num_coerce_bin(self
, other
, '/');
942 * rat.fdiv(numeric) -> float
944 * Performs division and returns the value as a Float.
946 * Rational(2, 3).fdiv(1) #=> 0.6666666666666666
947 * Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333
948 * Rational(2).fdiv(3) #=> 0.6666666666666666
951 nurat_fdiv(VALUE self
, VALUE other
)
955 return rb_rational_div(self
, rb_float_new(0.0));
956 if (FIXNUM_P(other
) && other
== LONG2FIX(1))
957 return nurat_to_f(self
);
958 div
= rb_rational_div(self
, other
);
959 if (RB_TYPE_P(div
, T_RATIONAL
))
960 return nurat_to_f(div
);
961 if (RB_FLOAT_TYPE_P(div
))
963 return rb_funcall(div
, idTo_f
, 0);
968 * rat ** numeric -> numeric
970 * Performs exponentiation.
972 * Rational(2) ** Rational(3) #=> (8/1)
973 * Rational(10) ** -2 #=> (1/100)
974 * Rational(10) ** -2.0 #=> 0.01
975 * Rational(-4) ** Rational(1, 2) #=> (0.0+2.0i)
976 * Rational(1, 2) ** 0 #=> (1/1)
977 * Rational(1, 2) ** 0.0 #=> 1.0
980 rb_rational_pow(VALUE self
, VALUE other
)
982 if (k_numeric_p(other
) && k_exact_zero_p(other
))
983 return f_rational_new_bang1(CLASS_OF(self
), ONE
);
985 if (k_rational_p(other
)) {
988 if (f_one_p(dat
->den
))
989 other
= dat
->num
; /* c14n */
992 /* Deal with special cases of 0**n and 1**n */
993 if (k_numeric_p(other
) && k_exact_p(other
)) {
995 if (f_one_p(dat
->den
)) {
996 if (f_one_p(dat
->num
)) {
997 return f_rational_new_bang1(CLASS_OF(self
), ONE
);
999 else if (f_minus_one_p(dat
->num
) && RB_INTEGER_TYPE_P(other
)) {
1000 return f_rational_new_bang1(CLASS_OF(self
), INT2FIX(rb_int_odd_p(other
) ? -1 : 1));
1002 else if (INT_ZERO_P(dat
->num
)) {
1003 if (rb_num_negative_p(other
)) {
1007 return f_rational_new_bang1(CLASS_OF(self
), ZERO
);
1014 if (FIXNUM_P(other
)) {
1020 if (INT_POSITIVE_P(other
)) {
1021 num
= rb_int_pow(dat
->num
, other
);
1022 den
= rb_int_pow(dat
->den
, other
);
1024 else if (INT_NEGATIVE_P(other
)) {
1025 num
= rb_int_pow(dat
->den
, rb_int_uminus(other
));
1026 den
= rb_int_pow(dat
->num
, rb_int_uminus(other
));
1032 if (RB_FLOAT_TYPE_P(num
)) { /* infinity due to overflow */
1033 if (RB_FLOAT_TYPE_P(den
))
1034 return DBL2NUM(nan(""));
1037 if (RB_FLOAT_TYPE_P(den
)) { /* infinity due to overflow */
1041 return f_rational_new2(CLASS_OF(self
), num
, den
);
1044 else if (RB_BIGNUM_TYPE_P(other
)) {
1045 rb_warn("in a**b, b may be too big");
1046 return rb_float_pow(nurat_to_f(self
), other
);
1048 else if (RB_FLOAT_TYPE_P(other
) || RB_TYPE_P(other
, T_RATIONAL
)) {
1049 return rb_float_pow(nurat_to_f(self
), other
);
1052 return rb_num_coerce_bin(self
, other
, idPow
);
1055 #define nurat_expt rb_rational_pow
1059 * rational <=> numeric -> -1, 0, +1, or nil
1061 * Returns -1, 0, or +1 depending on whether +rational+ is
1062 * less than, equal to, or greater than +numeric+.
1064 * +nil+ is returned if the two values are incomparable.
1066 * Rational(2, 3) <=> Rational(2, 3) #=> 0
1067 * Rational(5) <=> 5 #=> 0
1068 * Rational(2, 3) <=> Rational(1, 3) #=> 1
1069 * Rational(1, 3) <=> 1 #=> -1
1070 * Rational(1, 3) <=> 0.3 #=> 1
1072 * Rational(1, 3) <=> "0.3" #=> nil
1075 rb_rational_cmp(VALUE self
, VALUE other
)
1077 switch (TYPE(other
)) {
1083 if (dat
->den
== LONG2FIX(1))
1084 return rb_int_cmp(dat
->num
, other
); /* c14n */
1085 other
= f_rational_new_bang1(CLASS_OF(self
), other
);
1093 get_dat2(self
, other
);
1095 if (FIXNUM_P(adat
->num
) && FIXNUM_P(adat
->den
) &&
1096 FIXNUM_P(bdat
->num
) && FIXNUM_P(bdat
->den
)) {
1097 num1
= f_imul(FIX2LONG(adat
->num
), FIX2LONG(bdat
->den
));
1098 num2
= f_imul(FIX2LONG(bdat
->num
), FIX2LONG(adat
->den
));
1101 num1
= rb_int_mul(adat
->num
, bdat
->den
);
1102 num2
= rb_int_mul(bdat
->num
, adat
->den
);
1104 return rb_int_cmp(rb_int_minus(num1
, num2
), ZERO
);
1108 return rb_dbl_cmp(nurat_to_double(self
), RFLOAT_VALUE(other
));
1111 return rb_num_coerce_cmp(self
, other
, idCmp
);
1117 * rat == object -> true or false
1119 * Returns +true+ if +rat+ equals +object+ numerically.
1121 * Rational(2, 3) == Rational(2, 3) #=> true
1122 * Rational(5) == 5 #=> true
1123 * Rational(0) == 0.0 #=> true
1124 * Rational('1/3') == 0.33 #=> false
1125 * Rational('1/2') == '1/2' #=> false
1128 nurat_eqeq_p(VALUE self
, VALUE other
)
1130 if (RB_INTEGER_TYPE_P(other
)) {
1133 if (RB_INTEGER_TYPE_P(dat
->num
) && RB_INTEGER_TYPE_P(dat
->den
)) {
1134 if (INT_ZERO_P(dat
->num
) && INT_ZERO_P(other
))
1137 if (!FIXNUM_P(dat
->den
))
1139 if (FIX2LONG(dat
->den
) != 1)
1141 return rb_int_equal(dat
->num
, other
);
1144 const double d
= nurat_to_double(self
);
1145 return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d
, NUM2DBL(other
))));
1148 else if (RB_FLOAT_TYPE_P(other
)) {
1149 const double d
= nurat_to_double(self
);
1150 return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d
, RFLOAT_VALUE(other
))));
1152 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
1154 get_dat2(self
, other
);
1156 if (INT_ZERO_P(adat
->num
) && INT_ZERO_P(bdat
->num
))
1159 return RBOOL(rb_int_equal(adat
->num
, bdat
->num
) &&
1160 rb_int_equal(adat
->den
, bdat
->den
));
1164 return rb_equal(other
, self
);
1170 nurat_coerce(VALUE self
, VALUE other
)
1172 if (RB_INTEGER_TYPE_P(other
)) {
1173 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self
), other
), self
);
1175 else if (RB_FLOAT_TYPE_P(other
)) {
1176 return rb_assoc_new(other
, nurat_to_f(self
));
1178 else if (RB_TYPE_P(other
, T_RATIONAL
)) {
1179 return rb_assoc_new(other
, self
);
1181 else if (RB_TYPE_P(other
, T_COMPLEX
)) {
1182 if (!k_exact_zero_p(RCOMPLEX(other
)->imag
))
1183 return rb_assoc_new(other
, rb_Complex(self
, INT2FIX(0)));
1184 other
= RCOMPLEX(other
)->real
;
1185 if (RB_FLOAT_TYPE_P(other
)) {
1186 other
= float_to_r(other
);
1187 RBASIC_SET_CLASS(other
, CLASS_OF(self
));
1190 other
= f_rational_new_bang1(CLASS_OF(self
), other
);
1192 return rb_assoc_new(other
, self
);
1195 rb_raise(rb_eTypeError
, "%s can't be coerced into %s",
1196 rb_obj_classname(other
), rb_obj_classname(self
));
1202 * rat.positive? -> true or false
1204 * Returns +true+ if +rat+ is greater than 0.
1207 nurat_positive_p(VALUE self
)
1210 return RBOOL(INT_POSITIVE_P(dat
->num
));
1215 * rat.negative? -> true or false
1217 * Returns +true+ if +rat+ is less than 0.
1220 nurat_negative_p(VALUE self
)
1223 return RBOOL(INT_NEGATIVE_P(dat
->num
));
1228 * rat.abs -> rational
1229 * rat.magnitude -> rational
1231 * Returns the absolute value of +rat+.
1233 * (1/2r).abs #=> (1/2)
1234 * (-1/2r).abs #=> (1/2)
1239 rb_rational_abs(VALUE 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
);
1250 nurat_floor(VALUE self
)
1253 return rb_int_idiv(dat
->num
, dat
->den
);
1257 nurat_ceil(VALUE self
)
1260 return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat
->num
), dat
->den
));
1265 * rat.to_i -> integer
1267 * Returns the truncated value as an integer.
1269 * Equivalent to Rational#truncate.
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
1278 nurat_truncate(VALUE 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
);
1287 nurat_round_half_up(VALUE self
)
1289 VALUE num
, den
, neg
;
1295 neg
= INT_NEGATIVE_P(num
);
1298 num
= rb_int_uminus(num
);
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
);
1305 num
= rb_int_uminus(num
);
1311 nurat_round_half_down(VALUE self
)
1313 VALUE num
, den
, neg
;
1319 neg
= INT_NEGATIVE_P(num
);
1322 num
= rb_int_uminus(num
);
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
);
1330 num
= rb_int_uminus(num
);
1336 nurat_round_half_even(VALUE self
)
1338 VALUE num
, den
, neg
, qr
;
1344 neg
= INT_NEGATIVE_P(num
);
1347 num
= rb_int_uminus(num
);
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)));
1357 num
= rb_int_uminus(num
);
1363 f_round_common(int argc
, VALUE
*argv
, VALUE self
, VALUE (*func
)(VALUE
))
1367 if (rb_check_arity(argc
, 0, 1) == 0)
1368 return (*func
)(self
);
1372 if (!k_integer_p(n
))
1373 rb_raise(rb_eTypeError
, "not an integer");
1376 s
= rb_rational_mul(self
, b
);
1379 if (INT_NEGATIVE_P(n
))
1384 if (!k_rational_p(s
)) {
1385 s
= f_rational_new_bang1(CLASS_OF(self
), s
);
1390 s
= rb_rational_div(f_rational_new_bang1(CLASS_OF(self
), s
), b
);
1392 if (RB_TYPE_P(s
, T_RATIONAL
) && FIX2INT(rb_int_cmp(n
, ONE
)) < 0)
1393 s
= nurat_truncate(s
);
1399 rb_rational_floor(VALUE self
, int ndigits
)
1402 return nurat_floor(self
);
1405 VALUE n
= INT2NUM(ndigits
);
1406 return f_round_common(1, &n
, self
, nurat_floor
);
1412 * rat.floor([ndigits]) -> integer or rational
1414 * Returns the largest number less than or equal to +rat+ with
1415 * a precision of +ndigits+ decimal digits (default: 0).
1417 * When the precision is negative, the returned value is an integer
1418 * with at least <code>ndigits.abs</code> trailing zeros.
1420 * Returns a rational when +ndigits+ is positive,
1421 * otherwise returns an integer.
1423 * Rational(3).floor #=> 3
1424 * Rational(2, 3).floor #=> 0
1425 * Rational(-3, 2).floor #=> -2
1427 * # decimal - 1 2 3 . 4 5 6
1429 * # precision -3 -2 -1 0 +1 +2
1431 * Rational('-123.456').floor(+1).to_f #=> -123.5
1432 * Rational('-123.456').floor(-1) #=> -130
1435 nurat_floor_n(int argc
, VALUE
*argv
, VALUE self
)
1437 return f_round_common(argc
, argv
, self
, nurat_floor
);
1442 * rat.ceil([ndigits]) -> integer or rational
1444 * Returns the smallest number greater than or equal to +rat+ with
1445 * a precision of +ndigits+ decimal digits (default: 0).
1447 * When the precision is negative, the returned value is an integer
1448 * with at least <code>ndigits.abs</code> trailing zeros.
1450 * Returns a rational when +ndigits+ is positive,
1451 * otherwise returns an integer.
1453 * Rational(3).ceil #=> 3
1454 * Rational(2, 3).ceil #=> 1
1455 * Rational(-3, 2).ceil #=> -1
1457 * # decimal - 1 2 3 . 4 5 6
1459 * # precision -3 -2 -1 0 +1 +2
1461 * Rational('-123.456').ceil(+1).to_f #=> -123.4
1462 * Rational('-123.456').ceil(-1) #=> -120
1465 nurat_ceil_n(int argc
, VALUE
*argv
, VALUE self
)
1467 return f_round_common(argc
, argv
, self
, nurat_ceil
);
1472 * rat.truncate([ndigits]) -> integer or rational
1474 * Returns +rat+ truncated (toward zero) to
1475 * a precision of +ndigits+ decimal digits (default: 0).
1477 * When the precision is negative, the returned value is an integer
1478 * with at least <code>ndigits.abs</code> trailing zeros.
1480 * Returns a rational when +ndigits+ is positive,
1481 * otherwise returns an integer.
1483 * Rational(3).truncate #=> 3
1484 * Rational(2, 3).truncate #=> 0
1485 * Rational(-3, 2).truncate #=> -1
1487 * # decimal - 1 2 3 . 4 5 6
1489 * # precision -3 -2 -1 0 +1 +2
1491 * Rational('-123.456').truncate(+1).to_f #=> -123.4
1492 * Rational('-123.456').truncate(-1) #=> -120
1495 nurat_truncate_n(int argc
, VALUE
*argv
, VALUE self
)
1497 return f_round_common(argc
, argv
, self
, nurat_truncate
);
1502 * rat.round([ndigits] [, half: mode]) -> integer or rational
1504 * Returns +rat+ rounded to the nearest value with
1505 * a precision of +ndigits+ decimal digits (default: 0).
1507 * When the precision is negative, the returned value is an integer
1508 * with at least <code>ndigits.abs</code> trailing zeros.
1510 * Returns a rational when +ndigits+ is positive,
1511 * otherwise returns an integer.
1513 * Rational(3).round #=> 3
1514 * Rational(2, 3).round #=> 1
1515 * Rational(-3, 2).round #=> -2
1517 * # decimal - 1 2 3 . 4 5 6
1519 * # precision -3 -2 -1 0 +1 +2
1521 * Rational('-123.456').round(+1).to_f #=> -123.5
1522 * Rational('-123.456').round(-1) #=> -120
1524 * The optional +half+ keyword argument is available
1525 * similar to Float#round.
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)
1538 nurat_round_n(int argc
, VALUE
*argv
, VALUE self
)
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
);
1549 rb_flo_round_by_rational(int argc
, VALUE
*argv
, VALUE num
)
1551 return nurat_to_f(nurat_round_n(argc
, argv
, float_to_r(num
)));
1555 nurat_to_double(VALUE self
)
1558 if (!RB_INTEGER_TYPE_P(dat
->num
) || !RB_INTEGER_TYPE_P(dat
->den
)) {
1559 return NUM2DBL(dat
->num
) / NUM2DBL(dat
->den
);
1561 return rb_int_fdiv_double(dat
->num
, dat
->den
);
1568 * Returns the value as a Float.
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
1576 nurat_to_f(VALUE self
)
1578 return DBL2NUM(nurat_to_double(self
));
1587 * Rational(2).to_r #=> (2/1)
1588 * Rational(-8, 6).to_r #=> (-4/3)
1591 nurat_to_r(VALUE self
)
1596 #define id_ceil rb_intern("ceil")
1600 if (RB_INTEGER_TYPE_P(x
))
1602 if (RB_FLOAT_TYPE_P(x
))
1603 return rb_float_ceil(x
, 0);
1605 return rb_funcall(x
, id_ceil
, 0);
1608 #define id_quo idQuo
1610 f_quo(VALUE x
, VALUE y
)
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
));
1617 return rb_funcallv(x
, id_quo
, 1, &y
);
1620 #define f_reciprocal(x) f_quo(ONE, (x))
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."
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))).
1632 Call (integer-decode-float x). It returns a m,e,s=1 (mantissa,
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
1644 So, for given a and b (0 < a < b) we are searching a rational number
1646 Recursive algorithm fraction_between(a,b):
1649 then return c ; because a <= c < b, c integer
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)
1656 You can see that we are actually computing a continued fraction expansion.
1658 Algorithm (iterative):
1659 If x is rational, return x.
1660 Call (integer-decode-float x). It returns a m,e,s (mantissa,
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.
1671 then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
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.
1682 nurat_rationalize_internal(VALUE a
, VALUE b
, VALUE
*p
, VALUE
*q
)
1684 VALUE c
, k
, t
, p0
, p1
, p2
, q0
, q1
, q2
;
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
));
1706 *p
= f_add(f_mul(c
, p1
), p0
);
1707 *q
= f_add(f_mul(c
, q1
), q0
);
1712 * rat.rationalize -> self
1713 * rat.rationalize(eps) -> rational
1715 * Returns a simpler approximation of the value if the optional
1716 * argument +eps+ is given (rat-|eps| <= result <= rat+|eps|),
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)
1725 nurat_rationalize(int argc
, VALUE
*argv
, VALUE self
)
1727 VALUE e
, a
, b
, p
, q
;
1731 if (rb_check_arity(argc
, 0, 1) == 0)
1736 if (INT_NEGATIVE_P(dat
->num
)) {
1737 rat
= f_rational_new2(RBASIC_CLASS(self
), rb_int_uminus(dat
->num
), dat
->den
);
1740 a
= FIXNUM_ZERO_P(e
) ? rat
: rb_rational_minus(rat
, e
);
1741 b
= FIXNUM_ZERO_P(e
) ? rat
: rb_rational_plus(rat
, e
);
1746 nurat_rationalize_internal(a
, b
, &p
, &q
);
1748 RATIONAL_SET_NUM(rat
, rb_int_uminus(p
));
1749 RATIONAL_SET_DEN(rat
, q
);
1752 return f_rational_new2(CLASS_OF(self
), p
, q
);
1757 rb_rational_hash(VALUE self
)
1763 n
= rb_hash(dat
->num
);
1765 n
= rb_hash(dat
->den
);
1767 v
= rb_memhash(h
, sizeof(h
));
1772 nurat_hash(VALUE self
)
1774 return ST2FIX(rb_rational_hash(self
));
1779 f_format(VALUE self
, VALUE (*func
)(VALUE
))
1784 s
= (*func
)(dat
->num
);
1785 rb_str_cat2(s
, "/");
1786 rb_str_concat(s
, (*func
)(dat
->den
));
1793 * rat.to_s -> string
1795 * Returns the value as a string.
1797 * Rational(2).to_s #=> "2/1"
1798 * Rational(-8, 6).to_s #=> "-4/3"
1799 * Rational('1/2').to_s #=> "1/2"
1802 nurat_to_s(VALUE self
)
1804 return f_format(self
, f_to_s
);
1809 * rat.inspect -> string
1811 * Returns the value as a string for inspection.
1813 * Rational(2).inspect #=> "(2/1)"
1814 * Rational(-8, 6).inspect #=> "(-4/3)"
1815 * Rational('1/2').inspect #=> "(1/2)"
1818 nurat_inspect(VALUE self
)
1822 s
= rb_usascii_str_new2("(");
1823 rb_str_concat(s
, f_format(self
, f_inspect
));
1824 rb_str_cat2(s
, ")");
1831 nurat_dumper(VALUE self
)
1838 nurat_loader(VALUE self
, VALUE a
)
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
);
1857 nurat_marshal_dump(VALUE self
)
1862 a
= rb_assoc_new(dat
->num
, dat
->den
);
1863 rb_copy_generic_ivar(a
, self
);
1869 nurat_marshal_load(VALUE self
, VALUE a
)
1873 rb_check_frozen(self
);
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
));
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
);
1891 rb_rational_reciprocal(VALUE x
)
1894 return nurat_convert(CLASS_OF(x
), dat
->den
, dat
->num
, FALSE
);
1899 * int.gcd(other_int) -> integer
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.
1907 * ((1<<31)-1).gcd((1<<61)-1) #=> 1
1910 rb_gcd(VALUE self
, VALUE other
)
1912 other
= nurat_int_value(other
);
1913 return f_gcd(self
, other
);
1918 * int.lcm(other_int) -> integer
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.
1923 * 36.lcm(60) #=> 180
1926 * ((1<<31)-1).lcm((1<<61)-1) #=> 4951760154835678088235319297
1929 rb_lcm(VALUE self
, VALUE other
)
1931 other
= nurat_int_value(other
);
1932 return f_lcm(self
, other
);
1937 * int.gcdlcm(other_int) -> array
1939 * Returns an array with the greatest common divisor and
1940 * the least common multiple of the two integers, [gcd, lcm].
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]
1948 rb_gcdlcm(VALUE self
, VALUE other
)
1950 other
= nurat_int_value(other
);
1951 return rb_assoc_new(f_gcd(self
, other
), f_lcm(self
, other
));
1955 rb_rational_raw(VALUE x
, VALUE y
)
1957 if (! RB_INTEGER_TYPE_P(x
))
1959 if (! RB_INTEGER_TYPE_P(y
))
1961 if (INT_NEGATIVE_P(y
)) {
1962 x
= rb_int_uminus(x
);
1963 y
= rb_int_uminus(y
);
1965 return nurat_s_new_internal(rb_cRational
, x
, y
);
1969 rb_rational_new(VALUE x
, VALUE y
)
1971 return nurat_s_canonicalize_internal(rb_cRational
, x
, y
);
1975 rb_Rational(VALUE x
, VALUE y
)
1980 return nurat_s_convert(2, a
, rb_cRational
);
1984 rb_rational_num(VALUE rat
)
1986 return nurat_numerator(rat
);
1990 rb_rational_den(VALUE rat
)
1992 return nurat_denominator(rat
);
1995 #define id_numerator rb_intern("numerator")
1996 #define f_numerator(x) rb_funcall((x), id_numerator, 0)
1998 #define id_denominator rb_intern("denominator")
1999 #define f_denominator(x) rb_funcall((x), id_denominator, 0)
2001 #define id_to_r idTo_r
2002 #define f_to_r(x) rb_funcall((x), id_to_r, 0)
2006 * num.numerator -> integer
2008 * Returns the numerator.
2011 numeric_numerator(VALUE self
)
2013 return f_numerator(f_to_r(self
));
2018 * num.denominator -> integer
2020 * Returns the denominator (always positive).
2023 numeric_denominator(VALUE self
)
2025 return f_denominator(f_to_r(self
));
2031 * num.quo(int_or_rat) -> rat
2032 * num.quo(flo) -> flo
2034 * Returns the most exact division (rational for integers, float for floats).
2038 rb_numeric_quo(VALUE x
, VALUE y
)
2040 if (RB_TYPE_P(x
, T_COMPLEX
)) {
2041 return rb_complex_div(x
, y
);
2044 if (RB_FLOAT_TYPE_P(y
)) {
2045 return rb_funcallv(x
, idFdiv
, 1, &y
);
2048 x
= rb_convert_type(x
, T_RATIONAL
, "Rational", "to_r");
2049 return rb_rational_div(x
, y
);
2053 rb_rational_canonicalize(VALUE x
)
2055 if (RB_TYPE_P(x
, T_RATIONAL
)) {
2057 if (f_one_p(dat
->den
)) return dat
->num
;
2064 * flo.numerator -> integer
2066 * Returns the numerator. The result is machine dependent.
2068 * n = 0.3.numerator #=> 5404319552844595
2069 * d = 0.3.denominator #=> 18014398509481984
2072 * See also Float#denominator.
2075 rb_float_numerator(VALUE self
)
2077 double d
= RFLOAT_VALUE(self
);
2081 r
= float_to_r(self
);
2082 return nurat_numerator(r
);
2087 * flo.denominator -> integer
2089 * Returns the denominator (always positive). The result is machine
2092 * See also Float#numerator.
2095 rb_float_denominator(VALUE self
)
2097 double d
= RFLOAT_VALUE(self
);
2101 r
= float_to_r(self
);
2102 return nurat_denominator(r
);
2109 * Returns zero as a Rational:
2111 * nil.to_r # => (0/1)
2115 nilclass_to_r(VALUE self
)
2117 return rb_rational_new1(INT2FIX(0));
2122 * rationalize(eps = nil) -> (0/1)
2124 * Returns zero as a Rational:
2126 * nil.rationalize # => (0/1)
2128 * Argument +eps+ is ignored.
2132 nilclass_rationalize(int argc
, VALUE
*argv
, VALUE self
)
2134 rb_check_arity(argc
, 0, 1);
2135 return nilclass_to_r(self
);
2140 * int.to_r -> rational
2142 * Returns the value as a rational.
2145 * (1<<64).to_r #=> (18446744073709551616/1)
2148 integer_to_r(VALUE self
)
2150 return rb_rational_new1(self
);
2155 * int.rationalize([eps]) -> rational
2157 * Returns the value as a rational. The optional argument +eps+ is
2161 integer_rationalize(int argc
, VALUE
*argv
, VALUE self
)
2163 rb_check_arity(argc
, 0, 1);
2164 return integer_to_r(self
);
2168 float_decode_internal(VALUE self
, VALUE
*rf
, int *n
)
2172 f
= frexp(RFLOAT_VALUE(self
), n
);
2173 f
= ldexp(f
, DBL_MANT_DIG
);
2175 *rf
= rb_dbl2big(f
);
2180 * flt.to_r -> rational
2182 * Returns the value as a rational.
2184 * 2.0.to_r #=> (2/1)
2185 * 2.5.to_r #=> (5/2)
2186 * -0.75.to_r #=> (-3/4)
2187 * 0.0.to_r #=> (0/1)
2188 * 0.3.to_r #=> (5404319552844595/18014398509481984)
2190 * NOTE: 0.3.to_r isn't the same as "0.3".to_r. The latter is
2191 * equivalent to "3/10".to_r, but the former isn't so.
2193 * 0.3.to_r == 3/10r #=> false
2194 * "0.3".to_r == 3/10r #=> true
2196 * See also Float#rationalize.
2199 float_to_r(VALUE self
)
2204 float_decode_internal(self
, &f
, &n
);
2207 return rb_rational_new1(f
);
2209 return rb_rational_new1(rb_int_lshift(f
, INT2FIX(n
)));
2211 return rb_rational_new2(f
, rb_int_lshift(ONE
, INT2FIX(n
)));
2213 f
= rb_int_mul(f
, rb_int_pow(INT2FIX(FLT_RADIX
), n
));
2214 if (RB_TYPE_P(f
, T_RATIONAL
))
2216 return rb_rational_new1(f
);
2221 rb_flt_rationalize_with_prec(VALUE flt
, VALUE prec
)
2223 VALUE e
, a
, b
, p
, q
;
2230 return float_to_r(flt
);
2232 nurat_rationalize_internal(a
, b
, &p
, &q
);
2233 return rb_rational_new2(p
, q
);
2237 rb_flt_rationalize(VALUE flt
)
2239 VALUE a
, b
, f
, p
, q
, den
;
2242 float_decode_internal(flt
, &f
, &n
);
2243 if (INT_ZERO_P(f
) || n
>= 0)
2244 return rb_rational_new1(rb_int_lshift(f
, INT2FIX(n
)));
2247 VALUE radix_times_f
;
2249 radix_times_f
= rb_int_mul(INT2FIX(FLT_RADIX
), f
);
2250 #if FLT_RADIX == 2 && 0
2251 den
= rb_int_lshift(ONE
, INT2FIX(1-n
));
2253 den
= rb_int_positive_pow(FLT_RADIX
, 1-n
);
2256 a
= rb_int_minus(radix_times_f
, INT2FIX(FLT_RADIX
- 1));
2257 b
= rb_int_plus(radix_times_f
, INT2FIX(FLT_RADIX
- 1));
2261 return float_to_r(flt
);
2263 a
= rb_rational_new2(a
, den
);
2264 b
= rb_rational_new2(b
, den
);
2265 nurat_rationalize_internal(a
, b
, &p
, &q
);
2266 return rb_rational_new2(p
, q
);
2271 * flt.rationalize([eps]) -> rational
2273 * Returns a simpler approximation of the value (flt-|eps| <= result
2274 * <= flt+|eps|). If the optional argument +eps+ is not given,
2275 * it will be chosen automatically.
2277 * 0.3.rationalize #=> (3/10)
2278 * 1.333.rationalize #=> (1333/1000)
2279 * 1.333.rationalize(0.01) #=> (4/3)
2281 * See also Float#to_r.
2284 float_rationalize(int argc
, VALUE
*argv
, VALUE self
)
2286 double d
= RFLOAT_VALUE(self
);
2289 if (neg
) self
= DBL2NUM(-d
);
2291 if (rb_check_arity(argc
, 0, 1)) {
2292 rat
= rb_flt_rationalize_with_prec(self
, argv
[0]);
2295 rat
= rb_flt_rationalize(self
);
2297 if (neg
) RATIONAL_SET_NUM(rat
, rb_int_uminus(RRATIONAL(rat
)->num
));
2304 return (c
== '-' || c
== '+');
2308 read_sign(const char **s
, const char *const e
)
2312 if (*s
< e
&& issign(**s
)) {
2322 return (c
== 'e' || c
== 'E');
2326 negate_num(VALUE num
)
2328 if (FIXNUM_P(num
)) {
2329 return rb_int_uminus(num
);
2333 return rb_big_norm(num
);
2338 read_num(const char **s
, const char *const end
, VALUE
*num
, VALUE
*nexp
)
2340 VALUE fp
= ONE
, exp
, fn
= ZERO
, n
= ZERO
;
2341 int expsign
= 0, ok
= 0;
2346 if (*s
< end
&& **s
!= '.') {
2347 n
= rb_int_parse_cstr(*s
, end
-*s
, &e
, NULL
,
2348 10, RB_INT_PARSE_UNDERSCORE
);
2356 if (*s
< end
&& **s
== '.') {
2360 fp
= rb_int_parse_cstr(*s
, end
-*s
, &e
, &count
,
2361 10, RB_INT_PARSE_UNDERSCORE
);
2366 VALUE l
= f_expt10(*nexp
= SIZET2NUM(count
));
2367 n
= n
== ZERO
? fp
: rb_int_plus(rb_int_mul(*num
, l
), fp
);
2369 fn
= SIZET2NUM(count
);
2374 if (ok
&& *s
+ 1 < end
&& islettere(**s
)) {
2376 expsign
= read_sign(s
, end
);
2377 exp
= rb_int_parse_cstr(*s
, end
-*s
, &e
, NULL
,
2378 10, RB_INT_PARSE_UNDERSCORE
);
2383 if (expsign
== '-') {
2384 if (fn
!= ZERO
) exp
= rb_int_plus(exp
, fn
);
2387 if (fn
!= ZERO
) exp
= rb_int_minus(exp
, fn
);
2388 exp
= negate_num(exp
);
2397 inline static const char *
2398 skip_ws(const char *s
, const char *e
)
2400 while (s
< e
&& isspace((unsigned char)*s
))
2406 parse_rat(const char *s
, const char *const e
, int strict
, int raise
)
2409 VALUE num
, den
, nexp
, dexp
;
2412 sign
= read_sign(&s
, e
);
2414 if (!read_num(&s
, e
, &num
, &nexp
)) {
2415 if (strict
) return Qnil
;
2416 return nurat_s_alloc(rb_cRational
);
2419 if (s
< e
&& *s
== '/') {
2421 if (!read_num(&s
, e
, &den
, &dexp
)) {
2422 if (strict
) return Qnil
;
2425 else if (den
== ZERO
) {
2426 if (!raise
) return Qnil
;
2429 else if (strict
&& skip_ws(s
, e
) != e
) {
2433 nexp
= rb_int_minus(nexp
, dexp
);
2434 nurat_reduce(&num
, &den
);
2437 else if (strict
&& skip_ws(s
, e
) != e
) {
2442 if (INT_NEGATIVE_P(nexp
)) {
2444 if (FIXNUM_P(nexp
)) {
2445 mul
= f_expt10(LONG2NUM(-FIX2LONG(nexp
)));
2446 if (! RB_FLOAT_TYPE_P(mul
)) {
2447 num
= rb_int_mul(num
, mul
);
2451 return sign
== '-' ? DBL2NUM(-HUGE_VAL
) : DBL2NUM(HUGE_VAL
);
2455 if (FIXNUM_P(nexp
)) {
2456 div
= f_expt10(nexp
);
2457 if (! RB_FLOAT_TYPE_P(div
)) {
2458 den
= rb_int_mul(den
, div
);
2462 return sign
== '-' ? DBL2NUM(-0.0) : DBL2NUM(+0.0);
2465 nurat_reduce(&num
, &den
);
2469 num
= negate_num(num
);
2472 return rb_rational_raw(num
, den
);
2476 string_to_r_strict(VALUE self
, int raise
)
2480 rb_must_asciicompat(self
);
2482 num
= parse_rat(RSTRING_PTR(self
), RSTRING_END(self
), 1, raise
);
2484 if (!raise
) return Qnil
;
2485 rb_raise(rb_eArgError
, "invalid value for convert(): %+"PRIsVALUE
,
2489 if (RB_FLOAT_TYPE_P(num
) && !FLOAT_ZERO_P(num
)) {
2490 if (!raise
) return Qnil
;
2491 rb_raise(rb_eFloatDomainError
, "Infinity");
2498 * str.to_r -> rational
2500 * Returns the result of interpreting leading characters in +str+
2501 * as a rational. Leading whitespace and extraneous characters
2502 * past the end of a valid number are ignored.
2503 * Digit sequences can be separated by an underscore.
2504 * If there is not a valid number at the start of +str+,
2505 * zero is returned. This method never raises an exception.
2507 * ' 2 '.to_r #=> (2/1)
2508 * '300/2'.to_r #=> (150/1)
2509 * '-9.2'.to_r #=> (-46/5)
2510 * '-9.2e2'.to_r #=> (-920/1)
2511 * '1_234_567'.to_r #=> (1234567/1)
2512 * '21 June 09'.to_r #=> (21/1)
2513 * '21/06/09'.to_r #=> (7/2)
2514 * 'BWV 1079'.to_r #=> (0/1)
2516 * NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is
2517 * equivalent to "3/10".to_r, but the latter isn't so.
2519 * "0.3".to_r == 3/10r #=> true
2520 * 0.3.to_r == 3/10r #=> false
2522 * See also Kernel#Rational.
2525 string_to_r(VALUE self
)
2529 rb_must_asciicompat(self
);
2531 num
= parse_rat(RSTRING_PTR(self
), RSTRING_END(self
), 0, TRUE
);
2533 if (RB_FLOAT_TYPE_P(num
) && !FLOAT_ZERO_P(num
))
2534 rb_raise(rb_eFloatDomainError
, "Infinity");
2539 rb_cstr_to_rat(const char *s
, int strict
) /* for complex's internal */
2543 num
= parse_rat(s
, s
+ strlen(s
), strict
, TRUE
);
2545 if (RB_FLOAT_TYPE_P(num
) && !FLOAT_ZERO_P(num
))
2546 rb_raise(rb_eFloatDomainError
, "Infinity");
2551 to_rational(VALUE val
)
2553 return rb_convert_type_with_id(val
, T_RATIONAL
, "Rational", idTo_r
);
2557 nurat_convert(VALUE klass
, VALUE numv
, VALUE denv
, int raise
)
2559 VALUE a1
= numv
, a2
= denv
;
2562 RUBY_ASSERT(!UNDEF_P(a1
));
2564 if (NIL_P(a1
) || NIL_P(a2
)) {
2565 if (!raise
) return Qnil
;
2566 rb_raise(rb_eTypeError
, "can't convert nil into Rational");
2569 if (RB_TYPE_P(a1
, T_COMPLEX
)) {
2570 if (k_exact_zero_p(RCOMPLEX(a1
)->imag
))
2571 a1
= RCOMPLEX(a1
)->real
;
2574 if (RB_TYPE_P(a2
, T_COMPLEX
)) {
2575 if (k_exact_zero_p(RCOMPLEX(a2
)->imag
))
2576 a2
= RCOMPLEX(a2
)->real
;
2579 if (RB_INTEGER_TYPE_P(a1
)) {
2582 else if (RB_FLOAT_TYPE_P(a1
)) {
2583 a1
= float_to_r(a1
);
2585 else if (RB_TYPE_P(a1
, T_RATIONAL
)) {
2588 else if (RB_TYPE_P(a1
, T_STRING
)) {
2589 a1
= string_to_r_strict(a1
, raise
);
2590 if (!raise
&& NIL_P(a1
)) return Qnil
;
2592 else if (!rb_respond_to(a1
, idTo_r
)) {
2593 VALUE tmp
= rb_protect(rb_check_to_int
, a1
, NULL
);
2594 rb_set_errinfo(Qnil
);
2600 if (RB_INTEGER_TYPE_P(a2
)) {
2603 else if (RB_FLOAT_TYPE_P(a2
)) {
2604 a2
= float_to_r(a2
);
2606 else if (RB_TYPE_P(a2
, T_RATIONAL
)) {
2609 else if (RB_TYPE_P(a2
, T_STRING
)) {
2610 a2
= string_to_r_strict(a2
, raise
);
2611 if (!raise
&& NIL_P(a2
)) return Qnil
;
2613 else if (!UNDEF_P(a2
) && !rb_respond_to(a2
, idTo_r
)) {
2614 VALUE tmp
= rb_protect(rb_check_to_int
, a2
, NULL
);
2615 rb_set_errinfo(Qnil
);
2621 if (RB_TYPE_P(a1
, T_RATIONAL
)) {
2622 if (UNDEF_P(a2
) || (k_exact_one_p(a2
)))
2627 if (!RB_INTEGER_TYPE_P(a1
)) {
2629 VALUE result
= rb_protect(to_rational
, a1
, NULL
);
2630 rb_set_errinfo(Qnil
);
2633 return to_rational(a1
);
2637 if (!k_numeric_p(a1
)) {
2639 a1
= rb_protect(to_rational
, a1
, &state
);
2641 rb_set_errinfo(Qnil
);
2646 a1
= rb_check_convert_type_with_id(a1
, T_RATIONAL
, "Rational", idTo_r
);
2649 if (!k_numeric_p(a2
)) {
2651 a2
= rb_protect(to_rational
, a2
, &state
);
2653 rb_set_errinfo(Qnil
);
2658 a2
= rb_check_convert_type_with_id(a2
, T_RATIONAL
, "Rational", idTo_r
);
2661 if ((k_numeric_p(a1
) && k_numeric_p(a2
)) &&
2662 (!f_integer_p(a1
) || !f_integer_p(a2
))) {
2663 VALUE tmp
= rb_protect(to_rational
, a1
, &state
);
2668 rb_set_errinfo(Qnil
);
2670 return f_div(a1
, a2
);
2674 a1
= nurat_int_value(a1
);
2679 else if (!k_integer_p(a2
) && !raise
) {
2683 a2
= nurat_int_value(a2
);
2687 return nurat_s_canonicalize_internal(klass
, a1
, a2
);
2691 nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
)
2695 if (rb_scan_args(argc
, argv
, "11", &a1
, &a2
) == 1) {
2699 return nurat_convert(klass
, a1
, a2
, TRUE
);
2703 * A rational number can be represented as a pair of integer numbers:
2704 * a/b (b>0), where a is the numerator and b is the denominator.
2705 * Integer a equals rational a/1 mathematically.
2707 * You can create a \Rational object explicitly with:
2709 * - A {rational literal}[rdoc-ref:syntax/literals.rdoc@Rational+Literals].
2711 * You can convert certain objects to Rationals with:
2713 * - \Method #Rational.
2717 * Rational(1) #=> (1/1)
2718 * Rational(2, 3) #=> (2/3)
2719 * Rational(4, -6) #=> (-2/3) # Reduced.
2723 * You can also create rational objects from floating-point numbers or
2726 * Rational(0.3) #=> (5404319552844595/18014398509481984)
2727 * Rational('0.3') #=> (3/10)
2728 * Rational('2/3') #=> (2/3)
2730 * 0.3.to_r #=> (5404319552844595/18014398509481984)
2731 * '0.3'.to_r #=> (3/10)
2732 * '2/3'.to_r #=> (2/3)
2733 * 0.3.rationalize #=> (3/10)
2735 * A rational object is an exact number, which helps you to write
2736 * programs without any rounding errors.
2738 * 10.times.inject(0) {|t| t + 0.1 } #=> 0.9999999999999999
2739 * 10.times.inject(0) {|t| t + Rational('0.1') } #=> (1/1)
2741 * However, when an expression includes an inexact component (numerical value
2742 * or operation), it will produce an inexact result.
2744 * Rational(10) / 3 #=> (10/3)
2745 * Rational(10) / 3.0 #=> 3.3333333333333335
2747 * Rational(-8) ** Rational(1, 3)
2748 * #=> (1.0000000000000002+1.7320508075688772i)
2754 id_abs
= rb_intern_const("abs");
2755 id_integer_p
= rb_intern_const("integer?");
2756 id_i_num
= rb_intern_const("@numerator");
2757 id_i_den
= rb_intern_const("@denominator");
2759 rb_cRational
= rb_define_class("Rational", rb_cNumeric
);
2761 rb_define_alloc_func(rb_cRational
, nurat_s_alloc
);
2762 rb_undef_method(CLASS_OF(rb_cRational
), "allocate");
2764 rb_undef_method(CLASS_OF(rb_cRational
), "new");
2766 rb_define_global_function("Rational", nurat_f_rational
, -1);
2768 rb_define_method(rb_cRational
, "numerator", nurat_numerator
, 0);
2769 rb_define_method(rb_cRational
, "denominator", nurat_denominator
, 0);
2771 rb_define_method(rb_cRational
, "-@", rb_rational_uminus
, 0);
2772 rb_define_method(rb_cRational
, "+", rb_rational_plus
, 1);
2773 rb_define_method(rb_cRational
, "-", rb_rational_minus
, 1);
2774 rb_define_method(rb_cRational
, "*", rb_rational_mul
, 1);
2775 rb_define_method(rb_cRational
, "/", rb_rational_div
, 1);
2776 rb_define_method(rb_cRational
, "quo", rb_rational_div
, 1);
2777 rb_define_method(rb_cRational
, "fdiv", nurat_fdiv
, 1);
2778 rb_define_method(rb_cRational
, "**", nurat_expt
, 1);
2780 rb_define_method(rb_cRational
, "<=>", rb_rational_cmp
, 1);
2781 rb_define_method(rb_cRational
, "==", nurat_eqeq_p
, 1);
2782 rb_define_method(rb_cRational
, "coerce", nurat_coerce
, 1);
2784 rb_define_method(rb_cRational
, "positive?", nurat_positive_p
, 0);
2785 rb_define_method(rb_cRational
, "negative?", nurat_negative_p
, 0);
2786 rb_define_method(rb_cRational
, "abs", rb_rational_abs
, 0);
2787 rb_define_method(rb_cRational
, "magnitude", rb_rational_abs
, 0);
2789 rb_define_method(rb_cRational
, "floor", nurat_floor_n
, -1);
2790 rb_define_method(rb_cRational
, "ceil", nurat_ceil_n
, -1);
2791 rb_define_method(rb_cRational
, "truncate", nurat_truncate_n
, -1);
2792 rb_define_method(rb_cRational
, "round", nurat_round_n
, -1);
2794 rb_define_method(rb_cRational
, "to_i", nurat_truncate
, 0);
2795 rb_define_method(rb_cRational
, "to_f", nurat_to_f
, 0);
2796 rb_define_method(rb_cRational
, "to_r", nurat_to_r
, 0);
2797 rb_define_method(rb_cRational
, "rationalize", nurat_rationalize
, -1);
2799 rb_define_method(rb_cRational
, "hash", nurat_hash
, 0);
2801 rb_define_method(rb_cRational
, "to_s", nurat_to_s
, 0);
2802 rb_define_method(rb_cRational
, "inspect", nurat_inspect
, 0);
2804 rb_define_private_method(rb_cRational
, "marshal_dump", nurat_marshal_dump
, 0);
2806 compat
= rb_define_class_under(rb_cRational
, "compatible", rb_cObject
);
2807 rb_define_private_method(compat
, "marshal_load", nurat_marshal_load
, 1);
2808 rb_marshal_define_compat(rb_cRational
, compat
, nurat_dumper
, nurat_loader
);
2810 rb_define_method(rb_cInteger
, "gcd", rb_gcd
, 1);
2811 rb_define_method(rb_cInteger
, "lcm", rb_lcm
, 1);
2812 rb_define_method(rb_cInteger
, "gcdlcm", rb_gcdlcm
, 1);
2814 rb_define_method(rb_cNumeric
, "numerator", numeric_numerator
, 0);
2815 rb_define_method(rb_cNumeric
, "denominator", numeric_denominator
, 0);
2816 rb_define_method(rb_cNumeric
, "quo", rb_numeric_quo
, 1);
2818 rb_define_method(rb_cFloat
, "numerator", rb_float_numerator
, 0);
2819 rb_define_method(rb_cFloat
, "denominator", rb_float_denominator
, 0);
2821 rb_define_method(rb_cNilClass
, "to_r", nilclass_to_r
, 0);
2822 rb_define_method(rb_cNilClass
, "rationalize", nilclass_rationalize
, -1);
2823 rb_define_method(rb_cInteger
, "to_r", integer_to_r
, 0);
2824 rb_define_method(rb_cInteger
, "rationalize", integer_rationalize
, -1);
2825 rb_define_method(rb_cFloat
, "to_r", float_to_r
, 0);
2826 rb_define_method(rb_cFloat
, "rationalize", float_rationalize
, -1);
2828 rb_define_method(rb_cString
, "to_r", string_to_r
, 0);
2830 rb_define_private_method(CLASS_OF(rb_cRational
), "convert", nurat_s_convert
, -1);
2832 rb_provide("rational.so"); /* for backward compatibility */