diff options
Diffstat (limited to 'rational.c')
| -rw-r--r-- | rational.c | 230 |
1 files changed, 117 insertions, 113 deletions
diff --git a/rational.c b/rational.c index dfe2ad74eb..51078f81ad 100644 --- a/rational.c +++ b/rational.c @@ -22,9 +22,6 @@ # define USE_GMP 0 #endif #endif -#if USE_GMP -#include <gmp.h> -#endif #include "id.h" #include "internal.h" @@ -36,6 +33,15 @@ #include "internal/rational.h" #include "ruby_assert.h" +#if USE_GMP +RBIMPL_WARNING_PUSH() +# ifdef _MSC_VER +RBIMPL_WARNING_IGNORED(4146) /* for mpn_neg() */ +# endif +# include <gmp.h> +RBIMPL_WARNING_POP() +#endif + #define ZERO INT2FIX(0) #define ONE INT2FIX(1) #define TWO INT2FIX(2) @@ -389,8 +395,8 @@ f_gcd(VALUE x, VALUE y) { VALUE r = f_gcd_orig(x, y); if (f_nonzero_p(r)) { - assert(f_zero_p(f_mod(x, r))); - assert(f_zero_p(f_mod(y, r))); + RUBY_ASSERT(f_zero_p(f_mod(x, r))); + RUBY_ASSERT(f_zero_p(f_mod(y, r))); } return r; } @@ -413,11 +419,12 @@ f_lcm(VALUE x, VALUE y) inline static VALUE nurat_s_new_internal(VALUE klass, VALUE num, VALUE den) { - NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL | (RGENGC_WB_PROTECTED_RATIONAL ? FL_WB_PROTECTED : 0)); + NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL | (RGENGC_WB_PROTECTED_RATIONAL ? FL_WB_PROTECTED : 0), + sizeof(struct RRational), 0); RATIONAL_SET_NUM((VALUE)obj, num); RATIONAL_SET_DEN((VALUE)obj, den); - OBJ_FREEZE_RAW((VALUE)obj); + OBJ_FREEZE((VALUE)obj); return (VALUE)obj; } @@ -455,8 +462,8 @@ nurat_int_value(VALUE num) static void nurat_canonicalize(VALUE *num, VALUE *den) { - assert(num); assert(RB_INTEGER_TYPE_P(*num)); - assert(den); assert(RB_INTEGER_TYPE_P(*den)); + RUBY_ASSERT(num); RUBY_ASSERT(RB_INTEGER_TYPE_P(*num)); + RUBY_ASSERT(den); RUBY_ASSERT(RB_INTEGER_TYPE_P(*den)); if (INT_NEGATIVE_P(*den)) { *num = rb_int_uminus(*num); *den = rb_int_uminus(*den); @@ -496,16 +503,16 @@ nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den) inline static VALUE f_rational_new2(VALUE klass, VALUE x, VALUE y) { - assert(!k_rational_p(x)); - assert(!k_rational_p(y)); + RUBY_ASSERT(!k_rational_p(x)); + RUBY_ASSERT(!k_rational_p(y)); return nurat_s_canonicalize_internal(klass, x, y); } inline static VALUE f_rational_new_no_reduce2(VALUE klass, VALUE x, VALUE y) { - assert(!k_rational_p(x)); - assert(!k_rational_p(y)); + RUBY_ASSERT(!k_rational_p(x)); + RUBY_ASSERT(!k_rational_p(y)); return nurat_s_canonicalize_internal_no_reduce(klass, x, y); } @@ -602,14 +609,18 @@ nurat_denominator(VALUE self) /* * call-seq: - * -rat -> rational + * -self -> rational + * + * Returns +self+, negated: + * + * -(1/3r) # => (-1/3) + * -(-1/3r) # => (1/3) * - * Negates +rat+. */ VALUE rb_rational_uminus(VALUE self) { - const int unused = (assert(RB_TYPE_P(self, T_RATIONAL)), 0); + const int unused = (RUBY_ASSERT(RB_TYPE_P(self, T_RATIONAL)), 0); get_dat1(self); (void)unused; return f_rational_new2(CLASS_OF(self), rb_int_uminus(dat->num), dat->den); @@ -645,7 +656,7 @@ inline static VALUE f_imul(long x, long y) { VALUE r = f_imul_orig(x, y); - assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y)))); + RUBY_ASSERT(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y)))); return r; } #endif @@ -708,16 +719,27 @@ f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) static double nurat_to_double(VALUE self); /* - * call-seq: - * rat + numeric -> numeric + * call-seq: + * self + other -> numeric + * + * Returns the sum of +self+ and +other+: + * + * Rational(2, 3) + 0 # => (2/3) + * Rational(2, 3) + 1 # => (5/3) + * Rational(2, 3) + -1 # => (-1/3) + * + * Rational(2, 3) + Complex(1, 0) # => ((5/3)+0i) * - * Performs addition. + * Rational(2, 3) + Rational(1, 1) # => (5/3) + * Rational(2, 3) + Rational(3, 2) # => (13/6) + * Rational(2, 3) + Rational(3.0, 2.0) # => (13/6) + * Rational(2, 3) + Rational(3.1, 2.1) # => (30399297484750849/14186338826217063) + * + * For a computation involving Floats, the result may be inexact (see Float#+): + * + * Rational(2, 3) + 1.0 # => 1.6666666666666665 + * Rational(2, 3) + Complex(1.0, 0.0) # => (1.6666666666666665+0.0i) * - * Rational(2, 3) + Rational(2, 3) #=> (4/3) - * Rational(900) + Rational(1) #=> (901/1) - * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18) - * Rational(9, 8) + 4 #=> (41/8) - * Rational(20, 9) + 9.8 #=> 12.022222222222222 */ VALUE rb_rational_plus(VALUE self, VALUE other) @@ -750,9 +772,9 @@ rb_rational_plus(VALUE self, VALUE other) /* * call-seq: - * rat - numeric -> numeric + * self - other -> numeric * - * Performs subtraction. + * Returns the difference of +self+ and +other+: * * Rational(2, 3) - Rational(2, 3) #=> (0/1) * Rational(900) - Rational(1) #=> (899/1) @@ -794,7 +816,7 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) { VALUE num, den; - assert(RB_TYPE_P(self, T_RATIONAL)); + RUBY_ASSERT(RB_TYPE_P(self, T_RATIONAL)); /* Integer#** can return Rational with Float right now */ if (RB_FLOAT_TYPE_P(anum) || RB_FLOAT_TYPE_P(aden) || @@ -805,10 +827,10 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) return DBL2NUM(x); } - assert(RB_INTEGER_TYPE_P(anum)); - assert(RB_INTEGER_TYPE_P(aden)); - assert(RB_INTEGER_TYPE_P(bnum)); - assert(RB_INTEGER_TYPE_P(bden)); + RUBY_ASSERT(RB_INTEGER_TYPE_P(anum)); + RUBY_ASSERT(RB_INTEGER_TYPE_P(aden)); + RUBY_ASSERT(RB_INTEGER_TYPE_P(bnum)); + RUBY_ASSERT(RB_INTEGER_TYPE_P(bden)); if (k == '/') { VALUE t; @@ -846,15 +868,17 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) /* * call-seq: - * rat * numeric -> numeric + * self * other -> numeric + * + * Returns the numeric product of +self+ and +other+: * - * Performs multiplication. + * Rational(9, 8) * 4 #=> (9/2) + * Rational(20, 9) * 9.8 #=> 21.77777777777778 + * Rational(9, 8) * Complex(1, 2) # => ((9/8)+(9/4)*i) + * Rational(2, 3) * Rational(2, 3) #=> (4/9) + * Rational(900) * Rational(1) #=> (900/1) + * Rational(-2, 9) * Rational(-9, 2) #=> (1/1) * - * Rational(2, 3) * Rational(2, 3) #=> (4/9) - * Rational(900) * Rational(1) #=> (900/1) - * Rational(-2, 9) * Rational(-9, 2) #=> (1/1) - * Rational(9, 8) * 4 #=> (9/2) - * Rational(20, 9) * 9.8 #=> 21.77777777777778 */ VALUE rb_rational_mul(VALUE self, VALUE other) @@ -887,10 +911,9 @@ rb_rational_mul(VALUE self, VALUE other) /* * call-seq: - * rat / numeric -> numeric - * rat.quo(numeric) -> numeric + * self / other -> numeric * - * Performs division. + * Returns the quotient of +self+ and +other+: * * Rational(2, 3) / Rational(2, 3) #=> (1/1) * Rational(900) / Rational(1) #=> (900/1) @@ -964,9 +987,9 @@ nurat_fdiv(VALUE self, VALUE other) /* * call-seq: - * rat ** numeric -> numeric + * self ** exponent -> numeric * - * Performs exponentiation. + * Returns +self+ raised to the power +exponent+: * * Rational(2) ** Rational(3) #=> (8/1) * Rational(10) ** -2 #=> (1/100) @@ -1041,8 +1064,7 @@ rb_rational_pow(VALUE self, VALUE other) } } else if (RB_BIGNUM_TYPE_P(other)) { - rb_warn("in a**b, b may be too big"); - return rb_float_pow(nurat_to_f(self), other); + rb_raise(rb_eArgError, "exponent is too large"); } else if (RB_FLOAT_TYPE_P(other) || RB_TYPE_P(other, T_RATIONAL)) { return rb_float_pow(nurat_to_f(self), other); @@ -1055,20 +1077,30 @@ rb_rational_pow(VALUE self, VALUE other) /* * call-seq: - * rational <=> numeric -> -1, 0, +1, or nil + * self <=> other -> -1, 0, 1, or nil + * + * Compares +self+ and +other+. + * + * Returns: * - * Returns -1, 0, or +1 depending on whether +rational+ is - * less than, equal to, or greater than +numeric+. + * - +-1+, if +self+ is less than +other+. + * - +0+, if the two values are the same. + * - +1+, if +self+ is greater than +other+. + * - +nil+, if the two values are incomparable. * - * +nil+ is returned if the two values are incomparable. + * Examples: * - * Rational(2, 3) <=> Rational(2, 3) #=> 0 - * Rational(5) <=> 5 #=> 0 - * Rational(2, 3) <=> Rational(1, 3) #=> 1 - * Rational(1, 3) <=> 1 #=> -1 - * Rational(1, 3) <=> 0.3 #=> 1 + * Rational(2, 3) <=> Rational(4, 3) # => -1 + * Rational(2, 1) <=> Rational(2, 1) # => 0 + * Rational(2, 1) <=> 2 # => 0 + * Rational(2, 1) <=> 2.0 # => 0 + * Rational(2, 1) <=> Complex(2, 0) # => 0 + * Rational(4, 3) <=> Rational(2, 3) # => 1 + * Rational(4, 3) <=> :foo # => nil + * + * \Class \Rational includes module Comparable, + * each of whose methods uses Rational#<=> for comparison. * - * Rational(1, 3) <=> "0.3" #=> nil */ VALUE rb_rational_cmp(VALUE self, VALUE other) @@ -1113,9 +1145,9 @@ rb_rational_cmp(VALUE self, VALUE other) /* * call-seq: - * rat == object -> true or false + * self == other -> true or false * - * Returns +true+ if +rat+ equals +object+ numerically. + * Returns whether +self+ and +other+ are numerically equal: * * Rational(2, 3) == Rational(2, 3) #=> true * Rational(5) == 5 #=> true @@ -1232,7 +1264,6 @@ nurat_negative_p(VALUE self) * (1/2r).abs #=> (1/2) * (-1/2r).abs #=> (1/2) * - * Rational#magnitude is an alias for Rational#abs. */ VALUE @@ -1847,7 +1878,7 @@ nurat_loader(VALUE self, VALUE a) nurat_canonicalize(&num, &den); RATIONAL_SET_NUM((VALUE)dat, num); RATIONAL_SET_DEN((VALUE)dat, den); - OBJ_FREEZE_RAW(self); + OBJ_FREEZE(self); return self; } @@ -2104,32 +2135,6 @@ rb_float_denominator(VALUE self) /* * call-seq: - * nil.to_r -> (0/1) - * - * Returns zero as a rational. - */ -static VALUE -nilclass_to_r(VALUE self) -{ - return rb_rational_new1(INT2FIX(0)); -} - -/* - * call-seq: - * nil.rationalize([eps]) -> (0/1) - * - * Returns zero as a rational. The optional argument +eps+ is always - * ignored. - */ -static VALUE -nilclass_rationalize(int argc, VALUE *argv, VALUE self) -{ - rb_check_arity(argc, 0, 1); - return nilclass_to_r(self); -} - -/* - * call-seq: * int.to_r -> rational * * Returns the value as a rational. @@ -2488,31 +2493,32 @@ string_to_r_strict(VALUE self, int raise) /* * call-seq: - * str.to_r -> rational - * - * Returns the result of interpreting leading characters in +str+ - * as a rational. Leading whitespace and extraneous characters - * past the end of a valid number are ignored. - * Digit sequences can be separated by an underscore. - * If there is not a valid number at the start of +str+, - * zero is returned. This method never raises an exception. - * - * ' 2 '.to_r #=> (2/1) - * '300/2'.to_r #=> (150/1) - * '-9.2'.to_r #=> (-46/5) - * '-9.2e2'.to_r #=> (-920/1) - * '1_234_567'.to_r #=> (1234567/1) - * '21 June 09'.to_r #=> (21/1) - * '21/06/09'.to_r #=> (7/2) - * 'BWV 1079'.to_r #=> (0/1) - * - * NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is - * equivalent to "3/10".to_r, but the latter isn't so. + * str.to_r -> rational * - * "0.3".to_r == 3/10r #=> true - * 0.3.to_r == 3/10r #=> false + * Returns the result of interpreting leading characters in +self+ as a rational value: + * + * '123'.to_r # => (123/1) # Integer literal. + * '300/2'.to_r # => (150/1) # Rational literal. + * '-9.2'.to_r # => (-46/5) # Float literal. + * '-9.2e2'.to_r # => (-920/1) # Float literal. + * + * Ignores leading and trailing whitespace, and trailing non-numeric characters: + * + * ' 2 '.to_r # => (2/1) + * '21-Jun-09'.to_r # => (21/1) + * + * Returns \Rational zero if there are no leading numeric characters. + * + * 'BWV 1079'.to_r # => (0/1) + * + * NOTE: <tt>'0.3'.to_r</tt> is equivalent to <tt>3/10r</tt>, + * but is different from <tt>0.3.to_r</tt>: + * + * '0.3'.to_r # => (3/10) + * 3/10r # => (3/10) + * 0.3.to_r # => (5404319552844595/18014398509481984) * - * See also Kernel#Rational. + * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString]. */ static VALUE string_to_r(VALUE self) @@ -2552,7 +2558,7 @@ nurat_convert(VALUE klass, VALUE numv, VALUE denv, int raise) VALUE a1 = numv, a2 = denv; int state; - assert(!UNDEF_P(a1)); + RUBY_ASSERT(!UNDEF_P(a1)); if (NIL_P(a1) || NIL_P(a2)) { if (!raise) return Qnil; @@ -2703,7 +2709,7 @@ nurat_s_convert(int argc, VALUE *argv, VALUE klass) * * You can convert certain objects to Rationals with: * - * - \Method #Rational. + * - Method #Rational. * * Examples * @@ -2811,8 +2817,6 @@ Init_Rational(void) rb_define_method(rb_cFloat, "numerator", rb_float_numerator, 0); rb_define_method(rb_cFloat, "denominator", rb_float_denominator, 0); - rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0); - rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1); rb_define_method(rb_cInteger, "to_r", integer_to_r, 0); rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1); rb_define_method(rb_cFloat, "to_r", float_to_r, 0); |
