summaryrefslogtreecommitdiff
path: root/rational.c
diff options
context:
space:
mode:
Diffstat (limited to 'rational.c')
-rw-r--r--rational.c230
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);