summaryrefslogtreecommitdiff
path: root/numeric.c
diff options
context:
space:
mode:
Diffstat (limited to 'numeric.c')
-rw-r--r--numeric.c2398
1 files changed, 1455 insertions, 943 deletions
diff --git a/numeric.c b/numeric.c
index ded844a4cb..40629f56b6 100644
--- a/numeric.c
+++ b/numeric.c
@@ -2,16 +2,16 @@
numeric.c -
- $Author: matz $
- $Date: 2006/05/01 03:46:46 $
+ $Author$
created at: Fri Aug 13 18:33:09 JST 1993
- Copyright (C) 1993-2003 Yukihiro Matsumoto
+ Copyright (C) 1993-2007 Yukihiro Matsumoto
**********************************************************************/
-#include "ruby.h"
-#include "env.h"
+#include "ruby/ruby.h"
+#include "ruby/encoding.h"
+#include "ruby/util.h"
#include <ctype.h>
#include <math.h>
#include <stdio.h>
@@ -63,6 +63,44 @@
#define DBL_EPSILON 2.2204460492503131e-16
#endif
+#ifdef HAVE_INFINITY
+#elif BYTE_ORDER == LITTLE_ENDIAN
+const unsigned char rb_infinity[] = "\x00\x00\x80\x7f";
+#else
+const unsigned char rb_infinity[] = "\x7f\x80\x00\x00";
+#endif
+
+#ifdef HAVE_NAN
+#elif BYTE_ORDER == LITTLE_ENDIAN
+const unsigned char rb_nan[] = "\x00\x00\xc0\x7f";
+#else
+const unsigned char rb_nan[] = "\x7f\xc0\x00\x00";
+#endif
+
+extern double round(double);
+
+#ifndef HAVE_ROUND
+double
+round(double x)
+{
+ double f;
+
+ if (x > 0.0) {
+ f = floor(x);
+ x = f + (x - f >= 0.5);
+ }
+ else if (x < 0.0) {
+ f = ceil(x);
+ x = f - (f - x >= 0.5);
+ }
+ return x;
+}
+#endif
+
+static VALUE fix_uminus(VALUE num);
+static VALUE fix_mul(VALUE x, VALUE y);
+static VALUE int_pow(long x, unsigned long y);
+
static ID id_coerce, id_to_i, id_eq;
VALUE rb_cNumeric;
@@ -74,7 +112,7 @@ VALUE rb_eZeroDivError;
VALUE rb_eFloatDomainError;
void
-rb_num_zerodiv()
+rb_num_zerodiv(void)
{
rb_raise(rb_eZeroDivError, "divided by 0");
}
@@ -82,54 +120,51 @@ rb_num_zerodiv()
/*
* call-seq:
- * num.coerce(numeric) => array
- *
+ * num.coerce(numeric) -> array
+ *
* If <i>aNumeric</i> is the same type as <i>num</i>, returns an array
* containing <i>aNumeric</i> and <i>num</i>. Otherwise, returns an
* array with both <i>aNumeric</i> and <i>num</i> represented as
* <code>Float</code> objects. This coercion mechanism is used by
* Ruby to handle mixed-type numeric operations: it is intended to
* find a compatible common type between the two operands of the operator.
- *
+ *
* 1.coerce(2.5) #=> [2.5, 1.0]
* 1.2.coerce(3) #=> [3.0, 1.2]
* 1.coerce(2) #=> [2, 1]
*/
static VALUE
-num_coerce(x, y)
- VALUE x, y;
+num_coerce(VALUE x, VALUE y)
{
if (CLASS_OF(x) == CLASS_OF(y))
return rb_assoc_new(y, x);
- return rb_assoc_new(rb_Float(y), rb_Float(x));
+ x = rb_Float(x);
+ y = rb_Float(y);
+ return rb_assoc_new(y, x);
}
static VALUE
-coerce_body(x)
- VALUE *x;
+coerce_body(VALUE *x)
{
return rb_funcall(x[1], id_coerce, 1, x[0]);
}
static VALUE
-coerce_rescue(x)
- VALUE *x;
+coerce_rescue(VALUE *x)
{
volatile VALUE v = rb_inspect(x[1]);
rb_raise(rb_eTypeError, "%s can't be coerced into %s",
rb_special_const_p(x[1])?
- RSTRING(v)->ptr:
+ RSTRING_PTR(v):
rb_obj_classname(x[1]),
rb_obj_classname(x[0]));
return Qnil; /* dummy */
}
static int
-do_coerce(x, y, err)
- VALUE *x, *y;
- int err;
+do_coerce(VALUE *x, VALUE *y, int err)
{
VALUE ary;
VALUE a[2];
@@ -137,43 +172,40 @@ do_coerce(x, y, err)
a[0] = *x; a[1] = *y;
ary = rb_rescue(coerce_body, (VALUE)a, err?coerce_rescue:0, (VALUE)a);
- if (TYPE(ary) != T_ARRAY || RARRAY(ary)->len != 2) {
+ if (TYPE(ary) != T_ARRAY || RARRAY_LEN(ary) != 2) {
if (err) {
rb_raise(rb_eTypeError, "coerce must return [x, y]");
}
- return Qfalse;
+ return FALSE;
}
- *x = RARRAY(ary)->ptr[0];
- *y = RARRAY(ary)->ptr[1];
- return Qtrue;
+ *x = RARRAY_PTR(ary)[0];
+ *y = RARRAY_PTR(ary)[1];
+ return TRUE;
}
VALUE
-rb_num_coerce_bin(x, y)
- VALUE x, y;
+rb_num_coerce_bin(VALUE x, VALUE y, ID func)
{
- do_coerce(&x, &y, Qtrue);
- return rb_funcall(x, ruby_frame->orig_func, 1, y);
+ do_coerce(&x, &y, TRUE);
+ return rb_funcall(x, func, 1, y);
}
VALUE
-rb_num_coerce_cmp(x, y)
- VALUE x, y;
+rb_num_coerce_cmp(VALUE x, VALUE y, ID func)
{
- if (do_coerce(&x, &y, Qfalse))
- return rb_funcall(x, ruby_frame->orig_func, 1, y);
+ if (do_coerce(&x, &y, FALSE))
+ return rb_funcall(x, func, 1, y);
return Qnil;
}
VALUE
-rb_num_coerce_relop(x, y)
- VALUE x, y;
+rb_num_coerce_relop(VALUE x, VALUE y, ID func)
{
VALUE c, x0 = x, y0 = y;
- if (!do_coerce(&x, &y, Qfalse) ||
- NIL_P(c = rb_funcall(x, ruby_frame->orig_func, 1, y))) {
+ if (!do_coerce(&x, &y, FALSE) ||
+ NIL_P(c = rb_funcall(x, func, 1, y))) {
rb_cmperr(x0, y0);
return Qnil; /* not reached */
}
@@ -186,22 +218,22 @@ rb_num_coerce_relop(x, y)
*/
static VALUE
-num_sadded(x, name)
- VALUE x, name;
+num_sadded(VALUE x, VALUE name)
{
- ruby_frame = ruby_frame->prev; /* pop frame for "singleton_method_added" */
+ ID mid = rb_to_id(name);
+ /* ruby_frame = ruby_frame->prev; */ /* pop frame for "singleton_method_added" */
/* Numerics should be values; singleton_methods should not be added to them */
+ rb_remove_method_id(rb_singleton_class(x), mid);
rb_raise(rb_eTypeError,
"can't define singleton method \"%s\" for %s",
- rb_id2name(rb_to_id(name)),
- rb_obj_classname(x));
+ rb_id2name(mid),
+ rb_obj_classname(x));
return Qnil; /* not reached */
}
/* :nodoc: */
static VALUE
-num_init_copy(x, y)
- VALUE x, y;
+num_init_copy(VALUE x, VALUE y)
{
/* Numerics are immutable values, which should not be copied */
rb_raise(rb_eTypeError, "can't copy %s", rb_obj_classname(x));
@@ -210,90 +242,162 @@ num_init_copy(x, y)
/*
* call-seq:
- * +num => num
- *
+ * +num -> num
+ *
* Unary Plus---Returns the receiver's value.
*/
static VALUE
-num_uplus(num)
- VALUE num;
+num_uplus(VALUE num)
{
return num;
}
/*
* call-seq:
- * -num => numeric
- *
+ * num.i -> Complex(0,num)
+ *
+ * Returns the corresponding imaginary number.
+ * Not available for complex numbers.
+ */
+
+static VALUE
+num_imaginary(VALUE num)
+{
+ return rb_complex_new(INT2FIX(0), num);
+}
+
+
+/*
+ * call-seq:
+ * -num -> numeric
+ *
* Unary Minus---Returns the receiver's value, negated.
*/
static VALUE
-num_uminus(num)
- VALUE num;
+num_uminus(VALUE num)
{
VALUE zero;
zero = INT2FIX(0);
- do_coerce(&zero, &num, Qtrue);
+ do_coerce(&zero, &num, TRUE);
return rb_funcall(zero, '-', 1, num);
}
/*
* call-seq:
- * num.quo(numeric) => result
- *
- * Equivalent to <code>Numeric#/</code>, but overridden in subclasses.
+ * num.quo(numeric) -> real
+ *
+ * Returns most exact division (rational for integers, float for floats).
*/
static VALUE
-num_quo(x, y)
- VALUE x, y;
+num_quo(VALUE x, VALUE y)
{
- return rb_funcall(x, '/', 1, y);
+ return rb_funcall(rb_rational_raw1(x), '/', 1, y);
}
-static VALUE num_floor(VALUE num);
+/*
+ * call-seq:
+ * num.fdiv(numeric) -> float
+ *
+ * Returns float division.
+ */
+
+static VALUE
+num_fdiv(VALUE x, VALUE y)
+{
+ return rb_funcall(rb_Float(x), '/', 1, y);
+}
+
/*
* call-seq:
- * num.div(numeric) => integer
- *
+ * num.div(numeric) -> integer
+ *
* Uses <code>/</code> to perform division, then converts the result to
- * an integer. <code>Numeric</code> does not define the <code>/</code>
+ * an integer. <code>numeric</code> does not define the <code>/</code>
* operator; this is left to subclasses.
+ *
+ * Equivalent to
+ * <i>num</i>.<code>divmod(</code><i>aNumeric</i><code>)[0]</code>.
+ *
+ * See <code>Numeric#divmod</code>.
*/
static VALUE
-num_div(x, y)
- VALUE x, y;
+num_div(VALUE x, VALUE y)
{
- return num_floor(rb_funcall(x, '/', 1, y));
+ if (rb_equal(INT2FIX(0), y)) rb_num_zerodiv();
+ return rb_funcall(rb_funcall(x, '/', 1, y), rb_intern("floor"), 0);
}
+/*
+ * call-seq:
+ * num.modulo(numeric) -> real
+ *
+ * x.modulo(y) means x-y*(x/y).floor
+ *
+ * Equivalent to
+ * <i>num</i>.<code>divmod(</code><i>aNumeric</i><code>)[1]</code>.
+ *
+ * See <code>Numeric#divmod</code>.
+ */
+
+static VALUE
+num_modulo(VALUE x, VALUE y)
+{
+ return rb_funcall(x, '-', 1,
+ rb_funcall(y, '*', 1,
+ rb_funcall(x, rb_intern("div"), 1, y)));
+}
/*
* call-seq:
- * num.divmod( aNumeric ) -> anArray
- *
+ * num.remainder(numeric) -> real
+ *
+ * x.remainder(y) means x-y*(x/y).truncate
+ *
+ * See <code>Numeric#divmod</code>.
+ */
+
+static VALUE
+num_remainder(VALUE x, VALUE y)
+{
+ VALUE z = rb_funcall(x, '%', 1, y);
+
+ if ((!rb_equal(z, INT2FIX(0))) &&
+ ((RTEST(rb_funcall(x, '<', 1, INT2FIX(0))) &&
+ RTEST(rb_funcall(y, '>', 1, INT2FIX(0)))) ||
+ (RTEST(rb_funcall(x, '>', 1, INT2FIX(0))) &&
+ RTEST(rb_funcall(y, '<', 1, INT2FIX(0)))))) {
+ return rb_funcall(z, '-', 1, y);
+ }
+ return z;
+}
+
+/*
+ * call-seq:
+ * num.divmod(numeric) -> array
+ *
* Returns an array containing the quotient and modulus obtained by
- * dividing <i>num</i> by <i>aNumeric</i>. If <code>q, r =
+ * dividing <i>num</i> by <i>numeric</i>. If <code>q, r =
* x.divmod(y)</code>, then
*
- * q = floor(float(x)/float(y))
- * x = q*y + r
- *
+ * q = floor(x/y)
+ * x = q*y+r
+ *
* The quotient is rounded toward -infinity, as shown in the following table:
- *
+ *
* a | b | a.divmod(b) | a/b | a.modulo(b) | a.remainder(b)
* ------+-----+---------------+---------+-------------+---------------
* 13 | 4 | 3, 1 | 3 | 1 | 1
* ------+-----+---------------+---------+-------------+---------------
- * 13 | -4 | -4, -3 | -3 | -3 | 1
+ * 13 | -4 | -4, -3 | -4 | -3 | 1
* ------+-----+---------------+---------+-------------+---------------
* -13 | 4 | -4, 3 | -4 | 3 | -1
* ------+-----+---------------+---------+-------------+---------------
@@ -305,10 +409,11 @@ num_div(x, y)
* ------+-----+---------------+---------+-------------+---------------
* -11.5 | 4 | -3, 0.5 | -2.875 | 0.5 | -3.5
* ------+-----+---------------+---------+-------------+---------------
- * -11.5 | -4 | 2 -3.5 | 2.875 | -3.5 | -3.5
+ * -11.5 | -4 | 2, -3.5 | 2.875 | -3.5 | -3.5
*
*
* Examples
+ *
* 11.divmod(3) #=> [3, 2]
* 11.divmod(-3) #=> [-4, -1]
* 11.divmod(3.5) #=> [3, 0.5]
@@ -317,84 +422,53 @@ num_div(x, y)
*/
static VALUE
-num_divmod(x, y)
- VALUE x, y;
+num_divmod(VALUE x, VALUE y)
{
- return rb_assoc_new(num_div(x, y), rb_funcall(x, '%', 1, y));
+ return rb_assoc_new(num_div(x, y), num_modulo(x, y));
}
/*
* call-seq:
- * num.modulo(numeric) => result
- *
- * Equivalent to
- * <i>num</i>.<code>divmod(</code><i>aNumeric</i><code>)[1]</code>.
- */
-
-static VALUE
-num_modulo(x, y)
- VALUE x, y;
-{
- return rb_funcall(x, '%', 1, y);
-}
-
-/*
- * call-seq:
- * num.remainder(numeric) => result
- *
- * If <i>num</i> and <i>numeric</i> have different signs, returns
- * <em>mod</em>-<i>numeric</i>; otherwise, returns <em>mod</em>. In
- * both cases <em>mod</em> is the value
- * <i>num</i>.<code>modulo(</code><i>numeric</i><code>)</code>. The
- * differences between <code>remainder</code> and modulo
- * (<code>%</code>) are shown in the table under <code>Numeric#divmod</code>.
+ * num.real? -> true or false
+ *
+ * Returns <code>true</code> if <i>num</i> is a <code>Real</code>
+ * (i.e. non <code>Complex</code>).
*/
static VALUE
-num_remainder(x, y)
- VALUE x, y;
+num_real_p(VALUE num)
{
- VALUE z = rb_funcall(x, '%', 1, y);
-
- if ((!rb_equal(z, INT2FIX(0))) &&
- ((RTEST(rb_funcall(x, '<', 1, INT2FIX(0))) &&
- RTEST(rb_funcall(y, '>', 1, INT2FIX(0)))) ||
- (RTEST(rb_funcall(x, '>', 1, INT2FIX(0))) &&
- RTEST(rb_funcall(y, '<', 1, INT2FIX(0)))))) {
- return rb_funcall(z, '-', 1, y);
- }
- return z;
+ return Qtrue;
}
/*
* call-seq:
- * num.integer? -> true or false
- *
+ * num.integer? -> true or false
+ *
* Returns <code>true</code> if <i>num</i> is an <code>Integer</code>
* (including <code>Fixnum</code> and <code>Bignum</code>).
*/
static VALUE
-num_int_p(num)
- VALUE num;
+num_int_p(VALUE num)
{
return Qfalse;
}
/*
* call-seq:
- * num.abs => num or numeric
- *
+ * num.abs -> numeric
+ * num.magnitude -> numeric
+ *
* Returns the absolute value of <i>num</i>.
- *
+ *
* 12.abs #=> 12
* (-34.56).abs #=> 34.56
* -34.56.abs #=> 34.56
*/
static VALUE
-num_abs(num)
- VALUE num;
+num_abs(VALUE num)
{
if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) {
return rb_funcall(num, rb_intern("-@"), 0);
@@ -405,14 +479,13 @@ num_abs(num)
/*
* call-seq:
- * num.zero? => true or false
- *
+ * num.zero? -> true or false
+ *
* Returns <code>true</code> if <i>num</i> has a zero value.
*/
static VALUE
-num_zero_p(num)
- VALUE num;
+num_zero_p(VALUE num)
{
if (rb_equal(num, INT2FIX(0))) {
return Qtrue;
@@ -423,19 +496,18 @@ num_zero_p(num)
/*
* call-seq:
- * num.nonzero? => num or nil
- *
- * Returns <i>num</i> if <i>num</i> is not zero, <code>nil</code>
+ * num.nonzero? -> self or nil
+ *
+ * Returns +self+ if <i>num</i> is not zero, <code>nil</code>
* otherwise. This behavior is useful when chaining comparisons:
- *
+ *
* a = %w( z Bb bB bb BB a aA Aa AA A )
* b = a.sort {|a,b| (a.downcase <=> b.downcase).nonzero? || a <=> b }
* b #=> ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"]
*/
static VALUE
-num_nonzero_p(num)
- VALUE num;
+num_nonzero_p(VALUE num)
{
if (RTEST(rb_funcall(num, rb_intern("zero?"), 0, 0))) {
return Qnil;
@@ -445,43 +517,42 @@ num_nonzero_p(num)
/*
* call-seq:
- * num.to_int => integer
- *
+ * num.to_int -> integer
+ *
* Invokes the child class's <code>to_i</code> method to convert
* <i>num</i> to an integer.
*/
static VALUE
-num_to_int(num)
- VALUE num;
+num_to_int(VALUE num)
{
return rb_funcall(num, id_to_i, 0, 0);
}
/********************************************************************
- *
+ *
* Document-class: Float
*
- * <code>Float</code> objects represent real numbers using the native
- * architecture's double-precision floating point representation.
+ * <code>Float</code> objects represent inexact real numbers using
+ * the native architecture's double-precision floating point
+ * representation.
*/
VALUE
-rb_float_new(d)
- double d;
+rb_float_new(double d)
{
NEWOBJ(flt, struct RFloat);
OBJSETUP(flt, rb_cFloat, T_FLOAT);
- flt->value = d;
+ flt->float_value = d;
return (VALUE)flt;
}
/*
* call-seq:
- * flt.to_s => string
- *
+ * flt.to_s -> string
+ *
* Returns a string containing a representation of self. As well as a
* fixed or exponential form of the number, the call may return
* ``<code>NaN</code>'', ``<code>Infinity</code>'', and
@@ -489,33 +560,72 @@ rb_float_new(d)
*/
static VALUE
-flo_to_s(flt)
- VALUE flt;
+flo_to_s(VALUE flt)
{
- char buf[32];
- double value = RFLOAT(flt)->value;
+ char *ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve);
+ enum {decimal_mant = DBL_MANT_DIG-DBL_DIG};
+ enum {float_dig = DBL_DIG+1};
+ char buf[float_dig + (decimal_mant + CHAR_BIT - 1) / CHAR_BIT + 10];
+ double value = RFLOAT_VALUE(flt);
+ VALUE s;
char *p, *e;
+ int sign, decpt, digs;
if (isinf(value))
- return rb_str_new2(value < 0 ? "-Infinity" : "Infinity");
- else if(isnan(value))
- return rb_str_new2("NaN");
-
- sprintf(buf, "%#.15g", value); /* ensure to print decimal point */
- if (!(e = strchr(buf, 'e'))) {
- e = buf + strlen(buf);
- }
- if (!ISDIGIT(e[-1])) { /* reformat if ended with decimal point (ex 111111111111111.) */
- sprintf(buf, "%#.14e", value);
- if (!(e = strchr(buf, 'e'))) {
- e = buf + strlen(buf);
+ return rb_usascii_str_new2(value < 0 ? "-Infinity" : "Infinity");
+ else if (isnan(value))
+ return rb_usascii_str_new2("NaN");
+
+ p = ruby_dtoa(value, 0, 0, &decpt, &sign, &e);
+ s = sign ? rb_usascii_str_new_cstr("-") : rb_usascii_str_new(0, 0);
+ if ((digs = (int)(e - p)) >= (int)sizeof(buf)) digs = (int)sizeof(buf) - 1;
+ memcpy(buf, p, digs);
+ xfree(p);
+ if (decpt > 0) {
+ if (decpt < digs) {
+ memmove(buf + decpt + 1, buf + decpt, digs - decpt);
+ buf[decpt] = '.';
+ rb_str_cat(s, buf, digs + 1);
+ }
+ else if (decpt - digs < float_dig) {
+ long len;
+ char *ptr;
+ rb_str_cat(s, buf, digs);
+ rb_str_resize(s, (len = RSTRING_LEN(s)) + decpt - digs + 2);
+ ptr = RSTRING_PTR(s) + len;
+ if (decpt > digs) {
+ memset(ptr, '0', decpt - digs);
+ ptr += decpt - digs;
+ }
+ memcpy(ptr, ".0", 2);
}
+ else {
+ goto exp;
+ }
+ }
+ else if (decpt > -4) {
+ long len;
+ char *ptr;
+ rb_str_cat(s, "0.", 2);
+ rb_str_resize(s, (len = RSTRING_LEN(s)) - decpt + digs);
+ ptr = RSTRING_PTR(s);
+ memset(ptr += len, '0', -decpt);
+ memcpy(ptr -= decpt, buf, digs);
}
- p = e;
- while (p[-1]=='0' && ISDIGIT(p[-2]))
- p--;
- memmove(p, e, strlen(e)+1);
- return rb_str_new2(buf);
+ else {
+ exp:
+ if (digs > 1) {
+ memmove(buf + 2, buf + 1, digs - 1);
+ }
+ else {
+ buf[2] = '0';
+ digs++;
+ }
+ buf[1] = '.';
+ rb_str_cat(s, buf, digs + 1);
+ rb_str_catf(s, "e%+03d", decpt - 1);
+ }
+ return s;
}
/*
@@ -523,109 +633,103 @@ flo_to_s(flt)
*/
static VALUE
-flo_coerce(x, y)
- VALUE x, y;
+flo_coerce(VALUE x, VALUE y)
{
return rb_assoc_new(rb_Float(y), x);
}
/*
* call-seq:
- * -float => float
+ * -float -> float
*
* Returns float, negated.
*/
static VALUE
-flo_uminus(flt)
- VALUE flt;
+flo_uminus(VALUE flt)
{
- return rb_float_new(-RFLOAT(flt)->value);
+ return DBL2NUM(-RFLOAT_VALUE(flt));
}
/*
* call-seq:
- * float + other => float
+ * float + other -> float
*
* Returns a new float which is the sum of <code>float</code>
* and <code>other</code>.
*/
static VALUE
-flo_plus(x, y)
- VALUE x, y;
+flo_plus(VALUE x, VALUE y)
{
switch (TYPE(y)) {
case T_FIXNUM:
- return rb_float_new(RFLOAT(x)->value + (double)FIX2LONG(y));
+ return DBL2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y));
case T_BIGNUM:
- return rb_float_new(RFLOAT(x)->value + rb_big2dbl(y));
+ return DBL2NUM(RFLOAT_VALUE(x) + rb_big2dbl(y));
case T_FLOAT:
- return rb_float_new(RFLOAT(x)->value + RFLOAT(y)->value);
+ return DBL2NUM(RFLOAT_VALUE(x) + RFLOAT_VALUE(y));
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, '+');
}
}
/*
* call-seq:
- * float + other => float
+ * float - other -> float
*
* Returns a new float which is the difference of <code>float</code>
* and <code>other</code>.
*/
static VALUE
-flo_minus(x, y)
- VALUE x, y;
+flo_minus(VALUE x, VALUE y)
{
switch (TYPE(y)) {
case T_FIXNUM:
- return rb_float_new(RFLOAT(x)->value - (double)FIX2LONG(y));
+ return DBL2NUM(RFLOAT_VALUE(x) - (double)FIX2LONG(y));
case T_BIGNUM:
- return rb_float_new(RFLOAT(x)->value - rb_big2dbl(y));
+ return DBL2NUM(RFLOAT_VALUE(x) - rb_big2dbl(y));
case T_FLOAT:
- return rb_float_new(RFLOAT(x)->value - RFLOAT(y)->value);
+ return DBL2NUM(RFLOAT_VALUE(x) - RFLOAT_VALUE(y));
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, '-');
}
}
/*
* call-seq:
- * float * other => float
+ * float * other -> float
*
* Returns a new float which is the product of <code>float</code>
* and <code>other</code>.
*/
static VALUE
-flo_mul(x, y)
- VALUE x, y;
+flo_mul(VALUE x, VALUE y)
{
switch (TYPE(y)) {
case T_FIXNUM:
- return rb_float_new(RFLOAT(x)->value * (double)FIX2LONG(y));
+ return DBL2NUM(RFLOAT_VALUE(x) * (double)FIX2LONG(y));
case T_BIGNUM:
- return rb_float_new(RFLOAT(x)->value * rb_big2dbl(y));
+ return DBL2NUM(RFLOAT_VALUE(x) * rb_big2dbl(y));
case T_FLOAT:
- return rb_float_new(RFLOAT(x)->value * RFLOAT(y)->value);
+ return DBL2NUM(RFLOAT_VALUE(x) * RFLOAT_VALUE(y));
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, '*');
}
}
/*
* call-seq:
- * float / other => float
+ * float / other -> float
*
* Returns a new float which is the result of dividing
* <code>float</code> by <code>other</code>.
*/
static VALUE
-flo_div(x, y)
- VALUE x, y;
+flo_div(VALUE x, VALUE y)
{
long f_y;
double d;
@@ -633,25 +737,36 @@ flo_div(x, y)
switch (TYPE(y)) {
case T_FIXNUM:
f_y = FIX2LONG(y);
- return rb_float_new(RFLOAT(x)->value / (double)f_y);
+ return DBL2NUM(RFLOAT_VALUE(x) / (double)f_y);
case T_BIGNUM:
d = rb_big2dbl(y);
- return rb_float_new(RFLOAT(x)->value / d);
+ return DBL2NUM(RFLOAT_VALUE(x) / d);
case T_FLOAT:
- return rb_float_new(RFLOAT(x)->value / RFLOAT(y)->value);
+ return DBL2NUM(RFLOAT_VALUE(x) / RFLOAT_VALUE(y));
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, '/');
}
}
+/*
+ * call-seq:
+ * float.quo(numeric) -> float
+ *
+ * Returns float / numeric.
+ */
+
+static VALUE
+flo_quo(VALUE x, VALUE y)
+{
+ return rb_funcall(x, '/', 1, y);
+}
static void
-flodivmod(x, y, divp, modp)
- double x, y;
- double *divp, *modp;
+flodivmod(double x, double y, double *divp, double *modp)
{
double div, mod;
+ if (y == 0.0) rb_num_zerodiv();
#ifdef HAVE_FMOD
mod = fmod(x, y);
#else
@@ -662,7 +777,10 @@ flodivmod(x, y, divp, modp)
mod = x - z * y;
}
#endif
- div = (x - mod) / y;
+ if (isinf(x) && !isinf(y) && !isnan(y))
+ div = x;
+ else
+ div = (x - mod) / y;
if (y*mod < 0) {
mod += y;
div -= 1.0;
@@ -674,18 +792,17 @@ flodivmod(x, y, divp, modp)
/*
* call-seq:
- * flt % other => float
- * flt.modulo(other) => float
- *
+ * flt % other -> float
+ * flt.modulo(other) -> float
+ *
* Return the modulo after division of <code>flt</code> by <code>other</code>.
- *
+ *
* 6543.21.modulo(137) #=> 104.21
* 6543.21.modulo(137.24) #=> 92.9299999999996
*/
static VALUE
-flo_mod(x, y)
- VALUE x, y;
+flo_mod(VALUE x, VALUE y)
{
double fy, mod;
@@ -697,27 +814,36 @@ flo_mod(x, y)
fy = rb_big2dbl(y);
break;
case T_FLOAT:
- fy = RFLOAT(y)->value;
+ fy = RFLOAT_VALUE(y);
break;
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, '%');
}
- flodivmod(RFLOAT(x)->value, fy, 0, &mod);
- return rb_float_new(mod);
+ flodivmod(RFLOAT_VALUE(x), fy, 0, &mod);
+ return DBL2NUM(mod);
+}
+
+static VALUE
+dbl2ival(double d)
+{
+ if (FIXABLE(d)) {
+ d = round(d);
+ return LONG2FIX((long)d);
+ }
+ return rb_dbl2big(d);
}
/*
* call-seq:
- * flt.divmod(numeric) => array
- *
+ * flt.divmod(numeric) -> array
+ *
* See <code>Numeric#divmod</code>.
*/
static VALUE
-flo_divmod(x, y)
- VALUE x, y;
+flo_divmod(VALUE x, VALUE y)
{
- double fy, div, mod, val;
+ double fy, div, mod;
volatile VALUE a, b;
switch (TYPE(y)) {
@@ -728,62 +854,62 @@ flo_divmod(x, y)
fy = rb_big2dbl(y);
break;
case T_FLOAT:
- fy = RFLOAT(y)->value;
+ fy = RFLOAT_VALUE(y);
break;
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, rb_intern("divmod"));
}
- flodivmod(RFLOAT(x)->value, fy, &div, &mod);
- if (FIXABLE(div)) {
- val = div;
- a = LONG2FIX(val);
- }
- else {
- a = rb_dbl2big(div);
- }
- b = rb_float_new(mod);
+ flodivmod(RFLOAT_VALUE(x), fy, &div, &mod);
+ a = dbl2ival(div);
+ b = DBL2NUM(mod);
return rb_assoc_new(a, b);
}
/*
* call-seq:
*
- * flt ** other => float
+ * flt ** other -> float
*
* Raises <code>float</code> the <code>other</code> power.
+ *
+ * 2.0**3 #=> 8.0
*/
-
+
static VALUE
-flo_pow(x, y)
- VALUE x, y;
+flo_pow(VALUE x, VALUE y)
{
switch (TYPE(y)) {
case T_FIXNUM:
- return rb_float_new(pow(RFLOAT(x)->value, (double)FIX2LONG(y)));
+ return DBL2NUM(pow(RFLOAT_VALUE(x), (double)FIX2LONG(y)));
case T_BIGNUM:
- return rb_float_new(pow(RFLOAT(x)->value, rb_big2dbl(y)));
+ return DBL2NUM(pow(RFLOAT_VALUE(x), rb_big2dbl(y)));
case T_FLOAT:
- return rb_float_new(pow(RFLOAT(x)->value, RFLOAT(y)->value));
+ {
+ double dx = RFLOAT_VALUE(x);
+ double dy = RFLOAT_VALUE(y);
+ if (dx < 0 && dy != round(dy))
+ return rb_funcall(rb_complex_raw1(x), rb_intern("**"), 1, y);
+ return DBL2NUM(pow(dx, dy));
+ }
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, rb_intern("**"));
}
}
/*
* call-seq:
- * num.eql?(numeric) => true or false
- *
+ * num.eql?(numeric) -> true or false
+ *
* Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
* same type and have equal values.
- *
+ *
* 1 == 1.0 #=> true
* 1.eql?(1.0) #=> false
* (1.0).eql?(1.0) #=> true
*/
static VALUE
-num_eql(x, y)
- VALUE x, y;
+num_eql(VALUE x, VALUE y)
{
if (TYPE(x) != TYPE(y)) return Qfalse;
@@ -792,23 +918,21 @@ num_eql(x, y)
/*
* call-seq:
- * num <=> other -> 0 or nil
- *
+ * num <=> other -> 0 or nil
+ *
* Returns zero if <i>num</i> equals <i>other</i>, <code>nil</code>
* otherwise.
*/
static VALUE
-num_cmp(x, y)
- VALUE x, y;
+num_cmp(VALUE x, VALUE y)
{
if (x == y) return INT2FIX(0);
return Qnil;
}
static VALUE
-num_equal(x, y)
- VALUE x, y;
+num_equal(VALUE x, VALUE y)
{
if (x == y) return Qtrue;
return rb_funcall(y, id_eq, 1, x);
@@ -816,69 +940,66 @@ num_equal(x, y)
/*
* call-seq:
- * flt == obj => true or false
- *
+ * flt == obj -> true or false
+ *
* Returns <code>true</code> only if <i>obj</i> has the same value
* as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
* requires <i>obj</i> to be a <code>Float</code>.
- *
+ *
* 1.0 == 1 #=> true
- *
+ *
*/
static VALUE
-flo_eq(x, y)
- VALUE x, y;
+flo_eq(VALUE x, VALUE y)
{
volatile double a, b;
switch (TYPE(y)) {
case T_FIXNUM:
- b = FIX2LONG(y);
+ b = (double)FIX2LONG(y);
break;
case T_BIGNUM:
b = rb_big2dbl(y);
break;
case T_FLOAT:
- b = RFLOAT(y)->value;
+ b = RFLOAT_VALUE(y);
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
+#endif
break;
default:
return num_equal(x, y);
}
- a = RFLOAT(x)->value;
+ a = RFLOAT_VALUE(x);
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
+#endif
return (a == b)?Qtrue:Qfalse;
}
/*
* call-seq:
- * flt.hash => integer
+ * flt.hash -> integer
*
* Returns a hash code for this float.
*/
static VALUE
-flo_hash(num)
- VALUE num;
+flo_hash(VALUE num)
{
double d;
- char *c;
- int i, hash;
+ st_index_t hash;
- d = RFLOAT(num)->value;
- if (d == 0) d = fabs(d);
- c = (char*)&d;
- for (hash=0, i=0; i<sizeof(double);i++) {
- hash += c[i] * 971;
- }
- if (hash < 0) hash = -hash;
- return INT2FIX(hash);
+ d = RFLOAT_VALUE(num);
+ /* normalize -0.0 to 0.0 */
+ if (d == 0.0) d = 0.0;
+ hash = rb_memhash(&d, sizeof(d));
+ return LONG2FIX(hash);
}
VALUE
-rb_dbl_cmp(a, b)
- double a, b;
+rb_dbl_cmp(double a, double b)
{
if (isnan(a) || isnan(b)) return Qnil;
if (a == b) return INT2FIX(0);
@@ -889,53 +1010,61 @@ rb_dbl_cmp(a, b)
/*
* call-seq:
- * flt <=> numeric => -1, 0, +1
- *
- * Returns -1, 0, or +1 depending on whether <i>flt</i> is less than,
- * equal to, or greater than <i>numeric</i>. This is the basis for the
- * tests in <code>Comparable</code>.
+ * flt <=> real -> -1, 0, +1 or nil
+ *
+ * Returns -1, 0, +1 or nil depending on whether <i>flt</i> is less
+ * than, equal to, or greater than <i>real</i>. This is the basis for
+ * the tests in <code>Comparable</code>.
*/
static VALUE
-flo_cmp(x, y)
- VALUE x, y;
+flo_cmp(VALUE x, VALUE y)
{
double a, b;
- a = RFLOAT(x)->value;
+ a = RFLOAT_VALUE(x);
+ if (isnan(a)) return Qnil;
switch (TYPE(y)) {
case T_FIXNUM:
b = (double)FIX2LONG(y);
break;
case T_BIGNUM:
+ if (isinf(a)) {
+ if (a > 0.0) return INT2FIX(1);
+ else return INT2FIX(-1);
+ }
b = rb_big2dbl(y);
break;
case T_FLOAT:
- b = RFLOAT(y)->value;
+ b = RFLOAT_VALUE(y);
break;
default:
- return rb_num_coerce_cmp(x, y);
+ if (isinf(a) && (!rb_respond_to(y, rb_intern("infinite?")) ||
+ !RTEST(rb_funcall(y, rb_intern("infinite?"), 0, 0)))) {
+ if (a > 0.0) return INT2FIX(1);
+ return INT2FIX(-1);
+ }
+ return rb_num_coerce_cmp(x, y, rb_intern("<=>"));
}
return rb_dbl_cmp(a, b);
}
/*
* call-seq:
- * flt > other => true or false
+ * flt > real -> true or false
*
- * <code>true</code> if <code>flt</code> is greater than <code>other</code>.
+ * <code>true</code> if <code>flt</code> is greater than <code>real</code>.
*/
static VALUE
-flo_gt(x, y)
- VALUE x, y;
+flo_gt(VALUE x, VALUE y)
{
double a, b;
- a = RFLOAT(x)->value;
+ a = RFLOAT_VALUE(x);
switch (TYPE(y)) {
case T_FIXNUM:
b = (double)FIX2LONG(y);
@@ -946,32 +1075,35 @@ flo_gt(x, y)
break;
case T_FLOAT:
- b = RFLOAT(y)->value;
+ b = RFLOAT_VALUE(y);
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
+#endif
break;
default:
- return rb_num_coerce_relop(x, y);
+ return rb_num_coerce_relop(x, y, '>');
}
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
+#endif
return (a > b)?Qtrue:Qfalse;
}
/*
* call-seq:
- * flt >= other => true or false
+ * flt >= real -> true or false
*
- * <code>true</code> if <code>flt</code> is greater than
- * or equal to <code>other</code>.
+ * <code>true</code> if <code>flt</code> is greater than
+ * or equal to <code>real</code>.
*/
static VALUE
-flo_ge(x, y)
- VALUE x, y;
+flo_ge(VALUE x, VALUE y)
{
double a, b;
- a = RFLOAT(x)->value;
+ a = RFLOAT_VALUE(x);
switch (TYPE(y)) {
case T_FIXNUM:
b = (double)FIX2LONG(y);
@@ -982,31 +1114,34 @@ flo_ge(x, y)
break;
case T_FLOAT:
- b = RFLOAT(y)->value;
+ b = RFLOAT_VALUE(y);
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
+#endif
break;
default:
- return rb_num_coerce_relop(x, y);
+ return rb_num_coerce_relop(x, y, rb_intern(">="));
}
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
+#endif
return (a >= b)?Qtrue:Qfalse;
}
/*
* call-seq:
- * flt < other => true or false
+ * flt < real -> true or false
*
- * <code>true</code> if <code>flt</code> is less than <code>other</code>.
+ * <code>true</code> if <code>flt</code> is less than <code>real</code>.
*/
static VALUE
-flo_lt(x, y)
- VALUE x, y;
+flo_lt(VALUE x, VALUE y)
{
double a, b;
- a = RFLOAT(x)->value;
+ a = RFLOAT_VALUE(x);
switch (TYPE(y)) {
case T_FIXNUM:
b = (double)FIX2LONG(y);
@@ -1017,32 +1152,35 @@ flo_lt(x, y)
break;
case T_FLOAT:
- b = RFLOAT(y)->value;
+ b = RFLOAT_VALUE(y);
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
+#endif
break;
default:
- return rb_num_coerce_relop(x, y);
+ return rb_num_coerce_relop(x, y, '<');
}
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
+#endif
return (a < b)?Qtrue:Qfalse;
}
/*
* call-seq:
- * flt <= other => true or false
+ * flt <= real -> true or false
*
* <code>true</code> if <code>flt</code> is less than
- * or equal to <code>other</code>.
+ * or equal to <code>real</code>.
*/
static VALUE
-flo_le(x, y)
- VALUE x, y;
+flo_le(VALUE x, VALUE y)
{
double a, b;
- a = RFLOAT(x)->value;
+ a = RFLOAT_VALUE(x);
switch (TYPE(y)) {
case T_FIXNUM:
b = (double)FIX2LONG(y);
@@ -1053,88 +1191,91 @@ flo_le(x, y)
break;
case T_FLOAT:
- b = RFLOAT(y)->value;
+ b = RFLOAT_VALUE(y);
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
+#endif
break;
default:
- return rb_num_coerce_relop(x, y);
+ return rb_num_coerce_relop(x, y, rb_intern("<="));
}
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
+#endif
return (a <= b)?Qtrue:Qfalse;
}
/*
* call-seq:
- * flt.eql?(obj) => true or false
- *
+ * flt.eql?(obj) -> true or false
+ *
* Returns <code>true</code> only if <i>obj</i> is a
* <code>Float</code> with the same value as <i>flt</i>. Contrast this
* with <code>Float#==</code>, which performs type conversions.
- *
+ *
* 1.0.eql?(1) #=> false
*/
static VALUE
-flo_eql(x, y)
- VALUE x, y;
+flo_eql(VALUE x, VALUE y)
{
if (TYPE(y) == T_FLOAT) {
- double a = RFLOAT(x)->value;
- double b = RFLOAT(y)->value;
-
+ double a = RFLOAT_VALUE(x);
+ double b = RFLOAT_VALUE(y);
+#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a) || isnan(b)) return Qfalse;
- if (a == b) return Qtrue;
+#endif
+ if (a == b)
+ return Qtrue;
}
return Qfalse;
}
/*
* call-seq:
- * flt.to_f => flt
+ * flt.to_f -> self
*
- * As <code>flt</code> is already a float, returns <i>self</i>.
+ * As <code>flt</code> is already a float, returns +self+.
*/
static VALUE
-flo_to_f(num)
- VALUE num;
+flo_to_f(VALUE num)
{
return num;
}
/*
* call-seq:
- * flt.abs => float
- *
+ * flt.abs -> float
+ * flt.magnitude -> float
+ *
* Returns the absolute value of <i>flt</i>.
- *
+ *
* (-34.56).abs #=> 34.56
* -34.56.abs #=> 34.56
- *
+ *
*/
static VALUE
-flo_abs(flt)
- VALUE flt;
+flo_abs(VALUE flt)
{
- double val = fabs(RFLOAT(flt)->value);
- return rb_float_new(val);
+ double val = fabs(RFLOAT_VALUE(flt));
+ return DBL2NUM(val);
}
/*
* call-seq:
- * flt.zero? -> true or false
- *
+ * flt.zero? -> true or false
+ *
* Returns <code>true</code> if <i>flt</i> is 0.0.
- *
+ *
*/
static VALUE
-flo_zero_p(num)
- VALUE num;
+flo_zero_p(VALUE num)
{
- if (RFLOAT(num)->value == 0.0) {
+ if (RFLOAT_VALUE(num) == 0.0) {
return Qtrue;
}
return Qfalse;
@@ -1142,11 +1283,11 @@ flo_zero_p(num)
/*
* call-seq:
- * flt.nan? -> true or false
- *
+ * flt.nan? -> true or false
+ *
* Returns <code>true</code> if <i>flt</i> is an invalid IEEE floating
* point number.
- *
+ *
* a = -1.0 #=> -1.0
* a.nan? #=> false
* a = 0.0/0.0 #=> NaN
@@ -1154,31 +1295,29 @@ flo_zero_p(num)
*/
static VALUE
-flo_is_nan_p(num)
- VALUE num;
-{
- double value = RFLOAT(num)->value;
+flo_is_nan_p(VALUE num)
+{
+ double value = RFLOAT_VALUE(num);
return isnan(value) ? Qtrue : Qfalse;
}
/*
* call-seq:
- * flt.infinite? -> nil, -1, +1
- *
+ * flt.infinite? -> nil, -1, +1
+ *
* Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
* is finite, -infinity, or +infinity.
- *
+ *
* (0.0).infinite? #=> nil
* (-1.0/0.0).infinite? #=> -1
* (+1.0/0.0).infinite? #=> 1
*/
static VALUE
-flo_is_infinite_p(num)
- VALUE num;
-{
- double value = RFLOAT(num)->value;
+flo_is_infinite_p(VALUE num)
+{
+ double value = RFLOAT_VALUE(num);
if (isinf(value)) {
return INT2FIX( value < 0 ? -1 : 1 );
@@ -1189,19 +1328,18 @@ flo_is_infinite_p(num)
/*
* call-seq:
- * flt.finite? -> true or false
- *
+ * flt.finite? -> true or false
+ *
* Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
* point number (it is not infinite, and <code>nan?</code> is
* <code>false</code>).
- *
+ *
*/
static VALUE
-flo_is_finite_p(num)
- VALUE num;
-{
- double value = RFLOAT(num)->value;
+flo_is_finite_p(VALUE num)
+{
+ double value = RFLOAT_VALUE(num);
#if HAVE_FINITE
if (!finite(value))
@@ -1216,10 +1354,10 @@ flo_is_finite_p(num)
/*
* call-seq:
- * flt.floor => integer
- *
+ * flt.floor -> integer
+ *
* Returns the largest integer less than or equal to <i>flt</i>.
- *
+ *
* 1.2.floor #=> 1
* 2.0.floor #=> 2
* (-1.2).floor #=> -2
@@ -1227,26 +1365,25 @@ flo_is_finite_p(num)
*/
static VALUE
-flo_floor(num)
- VALUE num;
+flo_floor(VALUE num)
{
- double f = floor(RFLOAT(num)->value);
+ double f = floor(RFLOAT_VALUE(num));
long val;
if (!FIXABLE(f)) {
return rb_dbl2big(f);
}
- val = f;
+ val = (long)f;
return LONG2FIX(val);
}
/*
* call-seq:
- * flt.ceil => integer
- *
+ * flt.ceil -> integer
+ *
* Returns the smallest <code>Integer</code> greater than or equal to
* <i>flt</i>.
- *
+ *
* 1.2.ceil #=> 2
* 2.0.ceil #=> 2
* (-1.2).ceil #=> -1
@@ -1254,67 +1391,112 @@ flo_floor(num)
*/
static VALUE
-flo_ceil(num)
- VALUE num;
+flo_ceil(VALUE num)
{
- double f = ceil(RFLOAT(num)->value);
+ double f = ceil(RFLOAT_VALUE(num));
long val;
if (!FIXABLE(f)) {
return rb_dbl2big(f);
}
- val = f;
+ val = (long)f;
return LONG2FIX(val);
}
/*
* call-seq:
- * flt.round => integer
- *
- * Rounds <i>flt</i> to the nearest integer. Equivalent to:
- *
- * def round
- * return floor(self+0.5) if self > 0.0
- * return ceil(self-0.5) if self < 0.0
- * return 0.0
- * end
- *
+ * flt.round([ndigits]) -> integer or float
+ *
+ * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
+ * Precision may be negative. Returns a floating point number when ndigits
+ * is more than zero.
+ *
+ * 1.4.round #=> 1
* 1.5.round #=> 2
+ * 1.6.round #=> 2
* (-1.5).round #=> -2
- *
+ *
+ * 1.234567.round(2) #=> 1.23
+ * 1.234567.round(3) #=> 1.235
+ * 1.234567.round(4) #=> 1.2346
+ * 1.234567.round(5) #=> 1.23457
+ *
+ * 34567.89.round(-5) #=> 0
+ * 34567.89.round(-4) #=> 30000
+ * 34567.89.round(-3) #=> 35000
+ * 34567.89.round(-2) #=> 34600
+ * 34567.89.round(-1) #=> 34570
+ * 34567.89.round(0) #=> 34568
+ * 34567.89.round(1) #=> 34567.9
+ * 34567.89.round(2) #=> 34567.89
+ * 34567.89.round(3) #=> 34567.89
+ *
*/
static VALUE
-flo_round(num)
- VALUE num;
+flo_round(int argc, VALUE *argv, VALUE num)
{
- double f = RFLOAT(num)->value;
+ VALUE nd;
+ double number, f;
+ int ndigits = 0, i;
long val;
- if (f > 0.0) f = floor(f+0.5);
- if (f < 0.0) f = ceil(f-0.5);
+ if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) {
+ ndigits = NUM2INT(nd);
+ }
+ number = RFLOAT_VALUE(num);
+ f = 1.0;
+ i = abs(ndigits);
+ while (--i >= 0)
+ f = f*10.0;
- if (!FIXABLE(f)) {
- return rb_dbl2big(f);
+ if (isinf(f)) {
+ if (ndigits < 0) number = 0;
}
- val = f;
+ else {
+ if (ndigits < 0) {
+ double absnum = fabs(number);
+ if (absnum < f) return INT2FIX(0);
+ if (!FIXABLE(number)) {
+ VALUE f10 = int_pow(10, -ndigits);
+ VALUE n10 = f10;
+ if (number < 0) {
+ extern VALUE rb_big_uminus(VALUE x);
+ f10 = FIXNUM_P(f10) ? fix_uminus(f10) : rb_big_uminus(f10);
+ }
+ num = rb_big_idiv(rb_dbl2big(absnum), n10);
+ return FIXNUM_P(num) ? fix_mul(num, f10) : rb_big_mul(num, f10);
+ }
+ number /= f;
+ }
+ else number *= f;
+ number = round(number);
+ if (ndigits < 0) number *= f;
+ else number /= f;
+ }
+
+ if (ndigits > 0) return DBL2NUM(number);
+
+ if (!FIXABLE(number)) {
+ return rb_dbl2big(number);
+ }
+ val = (long)number;
return LONG2FIX(val);
}
/*
* call-seq:
- * flt.to_i => integer
- * flt.to_int => integer
- * flt.truncate => integer
- *
+ * flt.to_i -> integer
+ * flt.to_int -> integer
+ * flt.truncate -> integer
+ *
* Returns <i>flt</i> truncated to an <code>Integer</code>.
*/
static VALUE
-flo_truncate(num)
- VALUE num;
+flo_truncate(VALUE num)
{
- double f = RFLOAT(num)->value;
+ double f = RFLOAT_VALUE(num);
long val;
if (f > 0.0) f = floor(f);
@@ -1323,26 +1505,24 @@ flo_truncate(num)
if (!FIXABLE(f)) {
return rb_dbl2big(f);
}
- val = f;
+ val = (long)f;
return LONG2FIX(val);
}
-
/*
* call-seq:
- * num.floor => integer
- *
+ * num.floor -> integer
+ *
* Returns the largest integer less than or equal to <i>num</i>.
* <code>Numeric</code> implements this by converting <i>anInteger</i>
* to a <code>Float</code> and invoking <code>Float#floor</code>.
- *
+ *
* 1.floor #=> 1
* (-1).floor #=> -1
*/
static VALUE
-num_floor(num)
- VALUE num;
+num_floor(VALUE num)
{
return flo_floor(rb_Float(num));
}
@@ -1350,13 +1530,13 @@ num_floor(num)
/*
* call-seq:
- * num.ceil => integer
- *
+ * num.ceil -> integer
+ *
* Returns the smallest <code>Integer</code> greater than or equal to
* <i>num</i>. Class <code>Numeric</code> achieves this by converting
* itself to a <code>Float</code> then invoking
* <code>Float#ceil</code>.
- *
+ *
* 1.ceil #=> 1
* 1.2.ceil #=> 2
* (-1.2).ceil #=> -1
@@ -1364,80 +1544,107 @@ num_floor(num)
*/
static VALUE
-num_ceil(num)
- VALUE num;
+num_ceil(VALUE num)
{
return flo_ceil(rb_Float(num));
}
/*
* call-seq:
- * num.round => integer
- *
- * Rounds <i>num</i> to the nearest integer. <code>Numeric</code>
- * implements this by converting itself to a
- * <code>Float</code> and invoking <code>Float#round</code>.
+ * num.round([ndigits]) -> integer or float
+ *
+ * Rounds <i>num</i> to a given precision in decimal digits (default 0 digits).
+ * Precision may be negative. Returns a floating point number when ndigits
+ * is more than zero. <code>Numeric</code> implements this by converting itself
+ * to a <code>Float</code> and invoking <code>Float#round</code>.
*/
static VALUE
-num_round(num)
- VALUE num;
+num_round(int argc, VALUE* argv, VALUE num)
{
- return flo_round(rb_Float(num));
+ return flo_round(argc, argv, rb_Float(num));
}
/*
* call-seq:
- * num.truncate => integer
- *
+ * num.truncate -> integer
+ *
* Returns <i>num</i> truncated to an integer. <code>Numeric</code>
* implements this by converting its value to a float and invoking
* <code>Float#truncate</code>.
*/
static VALUE
-num_truncate(num)
- VALUE num;
+num_truncate(VALUE num)
{
return flo_truncate(rb_Float(num));
}
+int
+ruby_float_step(VALUE from, VALUE to, VALUE step, int excl)
+{
+ if (TYPE(from) == T_FLOAT || TYPE(to) == T_FLOAT || TYPE(step) == T_FLOAT) {
+ const double epsilon = DBL_EPSILON;
+ double beg = NUM2DBL(from);
+ double end = NUM2DBL(to);
+ double unit = NUM2DBL(step);
+ double n = (end - beg)/unit;
+ double err = (fabs(beg) + fabs(end) + fabs(end-beg)) / fabs(unit) * epsilon;
+ long i;
+
+ if (isinf(unit)) {
+ if (unit > 0 ? beg <= end : beg >= end) rb_yield(DBL2NUM(beg));
+ }
+ else {
+ if (err>0.5) err=0.5;
+ n = floor(n + err);
+ if (!excl || ((long)n)*unit+beg < end) n++;
+ for (i=0; i<n; i++) {
+ rb_yield(DBL2NUM(i*unit+beg));
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*
* call-seq:
- * num.step(limit, step ) {|i| block } => num
- *
+ * num.step(limit[, step]) {|i| block } -> self
+ * num.step(limit[, step]) -> an_enumerator
+ *
* Invokes <em>block</em> with the sequence of numbers starting at
- * <i>num</i>, incremented by <i>step</i> on each call. The loop
- * finishes when the value to be passed to the block is greater than
- * <i>limit</i> (if <i>step</i> is positive) or less than
- * <i>limit</i> (if <i>step</i> is negative). If all the arguments are
- * integers, the loop operates using an integer counter. If any of the
- * arguments are floating point numbers, all are converted to floats,
- * and the loop is executed <i>floor(n + n*epsilon)+ 1</i> times,
- * where <i>n = (limit - num)/step</i>. Otherwise, the loop
- * starts at <i>num</i>, uses either the <code><</code> or
- * <code>></code> operator to compare the counter against
- * <i>limit</i>, and increments itself using the <code>+</code>
- * operator.
- *
+ * <i>num</i>, incremented by <i>step</i> (default 1) on each
+ * call. The loop finishes when the value to be passed to the block
+ * is greater than <i>limit</i> (if <i>step</i> is positive) or less
+ * than <i>limit</i> (if <i>step</i> is negative). If all the
+ * arguments are integers, the loop operates using an integer
+ * counter. If any of the arguments are floating point numbers, all
+ * are converted to floats, and the loop is executed <i>floor(n +
+ * n*epsilon)+ 1</i> times, where <i>n = (limit -
+ * num)/step</i>. Otherwise, the loop starts at <i>num</i>, uses
+ * either the <code><</code> or <code>></code> operator to compare
+ * the counter against <i>limit</i>, and increments itself using the
+ * <code>+</code> operator.
+ *
+ * If no block is given, an enumerator is returned instead.
+ *
* 1.step(10, 2) { |i| print i, " " }
* Math::E.step(Math::PI, 0.2) { |f| print f, " " }
- *
+ *
* <em>produces:</em>
- *
+ *
* 1 3 5 7 9
* 2.71828182845905 2.91828182845905 3.11828182845905
*/
static VALUE
-num_step(argc, argv, from)
- int argc;
- VALUE *argv;
- VALUE from;
+num_step(int argc, VALUE *argv, VALUE from)
{
VALUE to, step;
+ RETURN_ENUMERATOR(from, argc, argv);
if (argc == 1) {
to = argv[0];
step = INT2FIX(1);
@@ -1448,7 +1655,7 @@ num_step(argc, argv, from)
step = argv[1];
}
else {
- rb_raise(rb_eArgError, "wrong number of arguments");
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc);
}
if (rb_equal(step, INT2FIX(0))) {
rb_raise(rb_eArgError, "step can't be 0");
@@ -1475,22 +1682,7 @@ num_step(argc, argv, from)
}
}
}
- else if (TYPE(from) == T_FLOAT || TYPE(to) == T_FLOAT || TYPE(step) == T_FLOAT) {
- const double epsilon = DBL_EPSILON;
- double beg = NUM2DBL(from);
- double end = NUM2DBL(to);
- double unit = NUM2DBL(step);
- double n = (end - beg)/unit;
- double err = (fabs(beg) + fabs(end) + fabs(end-beg)) / fabs(unit) * epsilon;
- long i;
-
- if (err>0.5) err=0.5;
- n = floor(n + err) + 1;
- for (i=0; i<n; i++) {
- rb_yield(rb_float_new(i*unit+beg));
- }
- }
- else {
+ else if (!ruby_float_step(from, to, step, FALSE)) {
VALUE i = from;
ID cmp;
@@ -1509,10 +1701,10 @@ num_step(argc, argv, from)
return from;
}
-long
-rb_num2long(val)
- VALUE val;
+SIGNED_VALUE
+rb_num2long(VALUE val)
{
+ again:
if (NIL_P(val)) {
rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
}
@@ -1521,16 +1713,16 @@ rb_num2long(val)
switch (TYPE(val)) {
case T_FLOAT:
- if (RFLOAT(val)->value <= (double)LONG_MAX
- && RFLOAT(val)->value >= (double)LONG_MIN) {
- return (long)(RFLOAT(val)->value);
+ if (RFLOAT_VALUE(val) <= (double)LONG_MAX
+ && RFLOAT_VALUE(val) >= (double)LONG_MIN) {
+ return (SIGNED_VALUE)(RFLOAT_VALUE(val));
}
else {
char buf[24];
char *s;
- sprintf(buf, "%-.10g", RFLOAT(val)->value);
- if (s = strchr(buf, ' ')) *s = '\0';
+ snprintf(buf, sizeof(buf), "%-.10g", RFLOAT_VALUE(val));
+ if ((s = strchr(buf, ' ')) != 0) *s = '\0';
rb_raise(rb_eRangeError, "float %s out of range of integer", buf);
}
@@ -1539,51 +1731,79 @@ rb_num2long(val)
default:
val = rb_to_int(val);
- return NUM2LONG(val);
+ goto again;
}
}
-unsigned long
-rb_num2ulong(val)
- VALUE val;
+VALUE
+rb_num2ulong(VALUE val)
{
- if (TYPE(val) == T_BIGNUM) {
+ again:
+ if (NIL_P(val)) {
+ rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
+ }
+
+ if (FIXNUM_P(val)) return FIX2LONG(val); /* this is FIX2LONG, inteneded */
+
+ switch (TYPE(val)) {
+ case T_FLOAT:
+ if (RFLOAT_VALUE(val) <= (double)LONG_MAX
+ && RFLOAT_VALUE(val) >= (double)LONG_MIN) {
+ return (VALUE)RFLOAT_VALUE(val);
+ }
+ else {
+ char buf[24];
+ char *s;
+
+ snprintf(buf, sizeof(buf), "%-.10g", RFLOAT_VALUE(val));
+ if ((s = strchr(buf, ' ')) != 0) *s = '\0';
+ rb_raise(rb_eRangeError, "float %s out of range of integer", buf);
+ }
+
+ case T_BIGNUM:
return rb_big2ulong(val);
+
+ default:
+ val = rb_to_int(val);
+ goto again;
}
- return (unsigned long)rb_num2long(val);
}
-#if SIZEOF_INT < SIZEOF_LONG
-static void
-check_int(num)
- long num;
+#if SIZEOF_INT < SIZEOF_VALUE
+void
+rb_out_of_int(SIGNED_VALUE num)
{
- const char *s;
+ rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to `int'",
+ num, num < 0 ? "small" : "big");
+}
- if (num < INT_MIN) {
- s = "small";
- }
- else if (num > INT_MAX) {
- s = "big";
- }
- else {
- return;
+static void
+check_int(SIGNED_VALUE num)
+{
+ if ((SIGNED_VALUE)(int)num != num) {
+ rb_out_of_int(num);
}
- rb_raise(rb_eRangeError, "integer %ld too %s to convert to `int'", num, s);
}
static void
-check_uint(num)
- unsigned long num;
+check_uint(VALUE num, VALUE sign)
{
- if (num > UINT_MAX) {
- rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned int'", num);
+ static const VALUE mask = ~(VALUE)UINT_MAX;
+
+ if (RTEST(sign)) {
+ /* minus */
+ if ((num & mask) != mask || (num & ~mask) <= INT_MAX + 1UL)
+ rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too small to convert to `unsigned int'", num);
+ }
+ else {
+ /* plus */
+ if ((num & mask) != 0)
+ rb_raise(rb_eRangeError, "integer %"PRIuVALUE " too big to convert to `unsigned int'", num);
}
}
long
-rb_num2int(val)
- VALUE val;
+rb_num2int(VALUE val)
{
long num = rb_num2long(val);
@@ -1592,8 +1812,7 @@ rb_num2int(val)
}
long
-rb_fix2int(val)
- VALUE val;
+rb_fix2int(VALUE val)
{
long num = FIXNUM_P(val)?FIX2LONG(val):rb_num2long(val);
@@ -1602,51 +1821,43 @@ rb_fix2int(val)
}
unsigned long
-rb_num2uint(val)
- VALUE val;
+rb_num2uint(VALUE val)
{
unsigned long num = rb_num2ulong(val);
- if (RTEST(rb_funcall(INT2FIX(0), '<', 1, val))) {
- check_uint(num);
- }
+ check_uint(num, rb_funcall(val, '<', 1, INT2FIX(0)));
return num;
}
unsigned long
-rb_fix2uint(val)
- VALUE val;
+rb_fix2uint(VALUE val)
{
unsigned long num;
if (!FIXNUM_P(val)) {
- return rb_num2uint(val);
+ return rb_num2uint(val);
}
num = FIX2ULONG(val);
- if (FIX2LONG(val) > 0) {
- check_uint(num);
- }
+
+ check_uint(num, rb_funcall(val, '<', 1, INT2FIX(0)));
return num;
}
#else
long
-rb_num2int(val)
- VALUE val;
+rb_num2int(VALUE val)
{
return rb_num2long(val);
}
long
-rb_fix2int(val)
- VALUE val;
+rb_fix2int(VALUE val)
{
return FIX2INT(val);
}
#endif
VALUE
-rb_num2fix(val)
- VALUE val;
+rb_num2fix(VALUE val)
{
long v;
@@ -1654,15 +1865,14 @@ rb_num2fix(val)
v = rb_num2long(val);
if (!FIXABLE(v))
- rb_raise(rb_eRangeError, "integer %ld out of range of fixnum", v);
+ rb_raise(rb_eRangeError, "integer %"PRIdVALUE " out of range of fixnum", v);
return LONG2FIX(v);
}
#if HAVE_LONG_LONG
LONG_LONG
-rb_num2ll(val)
- VALUE val;
+rb_num2ll(VALUE val)
{
if (NIL_P(val)) {
rb_raise(rb_eTypeError, "no implicit conversion from nil");
@@ -1671,41 +1881,40 @@ rb_num2ll(val)
if (FIXNUM_P(val)) return (LONG_LONG)FIX2LONG(val);
switch (TYPE(val)) {
- case T_FLOAT:
- if (RFLOAT(val)->value <= (double)LLONG_MAX
- && RFLOAT(val)->value >= (double)LLONG_MIN) {
- return (LONG_LONG)(RFLOAT(val)->value);
+ case T_FLOAT:
+ if (RFLOAT_VALUE(val) <= (double)LLONG_MAX
+ && RFLOAT_VALUE(val) >= (double)LLONG_MIN) {
+ return (LONG_LONG)(RFLOAT_VALUE(val));
}
else {
char buf[24];
char *s;
- sprintf(buf, "%-.10g", RFLOAT(val)->value);
- if (s = strchr(buf, ' ')) *s = '\0';
+ snprintf(buf, sizeof(buf), "%-.10g", RFLOAT_VALUE(val));
+ if ((s = strchr(buf, ' ')) != 0) *s = '\0';
rb_raise(rb_eRangeError, "float %s out of range of long long", buf);
}
- case T_BIGNUM:
+ case T_BIGNUM:
return rb_big2ll(val);
- case T_STRING:
+ case T_STRING:
rb_raise(rb_eTypeError, "no implicit conversion from string");
return Qnil; /* not reached */
- case T_TRUE:
- case T_FALSE:
+ case T_TRUE:
+ case T_FALSE:
rb_raise(rb_eTypeError, "no implicit conversion from boolean");
return Qnil; /* not reached */
default:
- val = rb_to_int(val);
- return NUM2LL(val);
+ val = rb_to_int(val);
+ return NUM2LL(val);
}
}
unsigned LONG_LONG
-rb_num2ull(val)
- VALUE val;
+rb_num2ull(VALUE val)
{
if (TYPE(val) == T_BIGNUM) {
return rb_big2ull(val);
@@ -1715,206 +1924,265 @@ rb_num2ull(val)
#endif /* HAVE_LONG_LONG */
-
/*
* Document-class: Integer
*
* <code>Integer</code> is the basis for the two concrete classes that
* hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
- *
+ *
*/
/*
* call-seq:
- * int.to_i => int
- * int.to_int => int
- * int.floor => int
- * int.ceil => int
- * int.round => int
- * int.truncate => int
+ * int.to_i -> integer
+ * int.to_int -> integer
+ * int.floor -> integer
+ * int.ceil -> integer
+ * int.round -> integer
+ * int.truncate -> integer
*
* As <i>int</i> is already an <code>Integer</code>, all these
* methods simply return the receiver.
*/
static VALUE
-int_to_i(num)
- VALUE num;
+int_to_i(VALUE num)
{
return num;
}
/*
* call-seq:
- * int.integer? -> true
- *
+ * int.integer? -> true
+ *
* Always returns <code>true</code>.
*/
static VALUE
-int_int_p(num)
- VALUE num;
+int_int_p(VALUE num)
{
return Qtrue;
}
/*
* call-seq:
- * int.next => integer
- * int.succ => integer
- *
- * Returns the <code>Integer</code> equal to <i>int</i> + 1.
- *
- * 1.next #=> 2
- * (-1).next #=> 0
+ * int.odd? -> true or false
+ *
+ * Returns <code>true</code> if <i>int</i> is an odd number.
*/
static VALUE
-int_succ(num)
- VALUE num;
+int_odd_p(VALUE num)
{
- if (FIXNUM_P(num)) {
- long i = FIX2LONG(num) + 1;
- return LONG2NUM(i);
+ if (rb_funcall(num, '%', 1, INT2FIX(2)) != INT2FIX(0)) {
+ return Qtrue;
}
- return rb_funcall(num, '+', 1, INT2FIX(1));
+ return Qfalse;
}
/*
* call-seq:
- * int.chr => string
- *
- * Returns a string containing the ASCII character represented by the
- * receiver's value.
- *
- * 65.chr #=> "A"
- * ?a.chr #=> "a"
- * 230.chr #=> "\346"
+ * int.even? -> true or false
+ *
+ * Returns <code>true</code> if <i>int</i> is an even number.
*/
static VALUE
-int_chr(num)
- VALUE num;
+int_even_p(VALUE num)
{
- char c;
- long i = NUM2LONG(num);
-
- if (i < 0 || 0xff < i)
- rb_raise(rb_eRangeError, "%ld out of char range", i);
- c = i;
- return rb_str_new(&c, 1);
+ if (rb_funcall(num, '%', 1, INT2FIX(2)) == INT2FIX(0)) {
+ return Qtrue;
+ }
+ return Qfalse;
}
-/********************************************************************
- *
- * Document-class: Fixnum
+/*
+ * call-seq:
+ * fixnum.next -> integer
+ * fixnum.succ -> integer
*
- * A <code>Fixnum</code> holds <code>Integer</code> values that can be
- * represented in a native machine word (minus 1 bit). If any operation
- * on a <code>Fixnum</code> exceeds this range, the value is
- * automatically converted to a <code>Bignum</code>.
- *
- * <code>Fixnum</code> objects have immediate value. This means that
- * when they are assigned or passed as parameters, the actual object is
- * passed, rather than a reference to that object. Assignment does not
- * alias <code>Fixnum</code> objects. There is effectively only one
- * <code>Fixnum</code> object instance for any given integer value, so,
- * for example, you cannot add a singleton method to a
- * <code>Fixnum</code>.
+ * Returns the <code>Integer</code> equal to <i>int</i> + 1.
+ *
+ * 1.next #=> 2
+ * (-1).next #=> 0
*/
+static VALUE
+fix_succ(VALUE num)
+{
+ long i = FIX2LONG(num) + 1;
+ return LONG2NUM(i);
+}
/*
- * call-seq:
- * Fixnum.induced_from(obj) => fixnum
+ * call-seq:
+ * int.next -> integer
+ * int.succ -> integer
*
- * Convert <code>obj</code> to a Fixnum. Works with numeric parameters.
- * Also works with Symbols, but this is deprecated.
+ * Returns the <code>Integer</code> equal to <i>int</i> + 1.
+ *
+ * 1.next #=> 2
+ * (-1).next #=> 0
*/
static VALUE
-rb_fix_induced_from(klass, x)
- VALUE klass, x;
+int_succ(VALUE num)
{
- return rb_num2fix(x);
+ if (FIXNUM_P(num)) {
+ long i = FIX2LONG(num) + 1;
+ return LONG2NUM(i);
+ }
+ return rb_funcall(num, '+', 1, INT2FIX(1));
}
/*
- * call-seq:
- * Integer.induced_from(obj) => fixnum, bignum
+ * call-seq:
+ * int.pred -> integer
*
- * Convert <code>obj</code> to an Integer.
+ * Returns the <code>Integer</code> equal to <i>int</i> - 1.
+ *
+ * 1.pred #=> 0
+ * (-1).pred #=> -2
*/
static VALUE
-rb_int_induced_from(klass, x)
- VALUE klass, x;
+int_pred(VALUE num)
+{
+ if (FIXNUM_P(num)) {
+ long i = FIX2LONG(num) - 1;
+ return LONG2NUM(i);
+ }
+ return rb_funcall(num, '-', 1, INT2FIX(1));
+}
+
+VALUE
+rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
{
- switch (TYPE(x)) {
- case T_FIXNUM:
- case T_BIGNUM:
- return x;
- case T_FLOAT:
- return rb_funcall(x, id_to_i, 0);
- default:
- rb_raise(rb_eTypeError, "failed to convert %s into Integer",
- rb_obj_classname(x));
+ int n;
+ VALUE str;
+ if ((n = rb_enc_codelen(code, enc)) <= 0) {
+ rb_raise(rb_eRangeError, "%d out of char range", code);
}
+ str = rb_enc_str_new(0, n, enc);
+ rb_enc_mbcput(code, RSTRING_PTR(str), enc);
+ return str;
}
/*
- * call-seq:
- * Float.induced_from(obj) => float
+ * call-seq:
+ * int.chr([encoding]) -> string
+ *
+ * Returns a string containing the character represented by the
+ * receiver's value according to +encoding+.
*
- * Convert <code>obj</code> to a float.
+ * 65.chr #=> "A"
+ * 230.chr #=> "\346"
+ * 255.chr(Encoding::UTF_8) #=> "\303\277"
*/
static VALUE
-rb_flo_induced_from(klass, x)
- VALUE klass, x;
+int_chr(int argc, VALUE *argv, VALUE num)
{
- switch (TYPE(x)) {
- case T_FIXNUM:
- case T_BIGNUM:
- return rb_funcall(x, rb_intern("to_f"), 0);
- case T_FLOAT:
- return x;
- default:
- rb_raise(rb_eTypeError, "failed to convert %s into Float",
- rb_obj_classname(x));
+ char c;
+ unsigned int i = NUM2UINT(num);
+ rb_encoding *enc;
+
+ switch (argc) {
+ case 0:
+ if (i < 0) {
+ out_of_range:
+ rb_raise(rb_eRangeError, "%d out of char range", i);
+ }
+ if (0xff < i) {
+ enc = rb_default_internal_encoding();
+ if (!enc) goto out_of_range;
+ goto decode;
+ }
+ c = (char)i;
+ if (i < 0x80) {
+ return rb_usascii_str_new(&c, 1);
+ }
+ else {
+ return rb_str_new(&c, 1);
+ }
+ case 1:
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
+ break;
}
+ enc = rb_to_encoding(argv[0]);
+ if (!enc) enc = rb_ascii8bit_encoding();
+ decode:
+ return rb_enc_uint_chr(i, enc);
}
/*
+ * call-seq:
+ * int.ord -> self
+ *
+ * Returns the int itself.
+ *
+ * ?a.ord #=> 97
+ *
+ * This method is intended for compatibility to
+ * character constant in Ruby 1.9.
+ * For example, ?a.ord returns 97 both in 1.8 and 1.9.
+ */
+
+static VALUE
+int_ord(num)
+ VALUE num;
+{
+ return num;
+}
+
+/********************************************************************
+ *
+ * Document-class: Fixnum
+ *
+ * A <code>Fixnum</code> holds <code>Integer</code> values that can be
+ * represented in a native machine word (minus 1 bit). If any operation
+ * on a <code>Fixnum</code> exceeds this range, the value is
+ * automatically converted to a <code>Bignum</code>.
+ *
+ * <code>Fixnum</code> objects have immediate value. This means that
+ * when they are assigned or passed as parameters, the actual object is
+ * passed, rather than a reference to that object. Assignment does not
+ * alias <code>Fixnum</code> objects. There is effectively only one
+ * <code>Fixnum</code> object instance for any given integer value, so,
+ * for example, you cannot add a singleton method to a
+ * <code>Fixnum</code>.
+ */
+
+
+/*
* call-seq:
- * -fix => integer
+ * -fix -> integer
*
* Negates <code>fix</code> (which might return a Bignum).
*/
static VALUE
-fix_uminus(num)
- VALUE num;
+fix_uminus(VALUE num)
{
return LONG2NUM(-FIX2LONG(num));
}
VALUE
-rb_fix2str(x, base)
- VALUE x;
- int base;
+rb_fix2str(VALUE x, int base)
{
extern const char ruby_digitmap[];
- char buf[SIZEOF_LONG*CHAR_BIT + 2], *b = buf + sizeof buf;
+ char buf[SIZEOF_VALUE*CHAR_BIT + 2], *b = buf + sizeof buf;
long val = FIX2LONG(x);
int neg = 0;
if (base < 2 || 36 < base) {
- rb_raise(rb_eArgError, "illegal radix %d", base);
+ rb_raise(rb_eArgError, "invalid radix %d", base);
}
if (val == 0) {
- return rb_str_new2("0");
+ return rb_usascii_str_new2("0");
}
if (val < 0) {
val = -val;
@@ -1928,16 +2196,16 @@ rb_fix2str(x, base)
*--b = '-';
}
- return rb_str_new2(b);
+ return rb_usascii_str_new2(b);
}
/*
* call-seq:
- * fix.to_s( base=10 ) -> aString
- *
+ * fix.to_s(base=10) -> string
+ *
* Returns a string containing the representation of <i>fix</i> radix
* <i>base</i> (between 2 and 36).
- *
+ *
* 12345.to_s #=> "12345"
* 12345.to_s(2) #=> "11000000111001"
* 12345.to_s(8) #=> "30071"
@@ -1947,33 +2215,32 @@ rb_fix2str(x, base)
*
*/
static VALUE
-fix_to_s(argc, argv, x)
- int argc;
- VALUE *argv;
- VALUE x;
+fix_to_s(int argc, VALUE *argv, VALUE x)
{
- VALUE b;
int base;
- rb_scan_args(argc, argv, "01", &b);
if (argc == 0) base = 10;
- else base = NUM2INT(b);
+ else {
+ VALUE b;
+
+ rb_scan_args(argc, argv, "01", &b);
+ base = NUM2INT(b);
+ }
return rb_fix2str(x, base);
}
/*
* call-seq:
- * fix + numeric => numeric_result
+ * fix + numeric -> numeric_result
*
* Performs addition: the class of the resulting object depends on
- * the class of <code>numeric</code> and on the magnitude of the
+ * the class of <code>numeric</code> and on the magnitude of the
* result.
*/
static VALUE
-fix_plus(x, y)
- VALUE x, y;
+fix_plus(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
long a, b, c;
@@ -1982,31 +2249,31 @@ fix_plus(x, y)
a = FIX2LONG(x);
b = FIX2LONG(y);
c = a + b;
- r = LONG2FIX(c);
+ r = LONG2NUM(c);
- if (FIX2LONG(r) != c) {
- r = rb_big_plus(rb_int2big(a), rb_int2big(b));
- }
return r;
}
- if (TYPE(y) == T_FLOAT) {
- return rb_float_new((double)FIX2LONG(x) + RFLOAT(y)->value);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return rb_big_plus(y, x);
+ case T_FLOAT:
+ return DBL2NUM((double)FIX2LONG(x) + RFLOAT_VALUE(y));
+ default:
+ return rb_num_coerce_bin(x, y, '+');
}
- return rb_num_coerce_bin(x, y);
}
/*
* call-seq:
- * fix - numeric => numeric_result
+ * fix - numeric -> numeric_result
*
* Performs subtraction: the class of the resulting object depends on
- * the class of <code>numeric</code> and on the magnitude of the
+ * the class of <code>numeric</code> and on the magnitude of the
* result.
*/
static VALUE
-fix_minus(x, y)
- VALUE x, y;
+fix_minus(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
long a, b, c;
@@ -2015,58 +2282,82 @@ fix_minus(x, y)
a = FIX2LONG(x);
b = FIX2LONG(y);
c = a - b;
- r = LONG2FIX(c);
+ r = LONG2NUM(c);
- if (FIX2LONG(r) != c) {
- r = rb_big_minus(rb_int2big(a), rb_int2big(b));
- }
return r;
}
- if (TYPE(y) == T_FLOAT) {
- return rb_float_new((double)FIX2LONG(x) - RFLOAT(y)->value);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ x = rb_int2big(FIX2LONG(x));
+ return rb_big_minus(x, y);
+ case T_FLOAT:
+ return DBL2NUM((double)FIX2LONG(x) - RFLOAT_VALUE(y));
+ default:
+ return rb_num_coerce_bin(x, y, '-');
}
- return rb_num_coerce_bin(x, y);
}
+#define SQRT_LONG_MAX ((SIGNED_VALUE)1<<((SIZEOF_LONG*CHAR_BIT-1)/2))
+/*tests if N*N would overflow*/
+#define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((n)>=-SQRT_LONG_MAX))
+
/*
* call-seq:
- * fix * numeric => numeric_result
+ * fix * numeric -> numeric_result
*
* Performs multiplication: the class of the resulting object depends on
- * the class of <code>numeric</code> and on the magnitude of the
+ * the class of <code>numeric</code> and on the magnitude of the
* result.
*/
static VALUE
-fix_mul(x, y)
- VALUE x, y;
+fix_mul(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- long a, b, c;
+#ifdef __HP_cc
+/* avoids an optimization bug of HP aC++/ANSI C B3910B A.06.05 [Jul 25 2005] */
+ volatile
+#endif
+ long a, b;
+#if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
+ LONG_LONG d;
+#else
+ volatile long c;
VALUE r;
+#endif
a = FIX2LONG(x);
- if (a == 0) return x;
-
b = FIX2LONG(y);
+
+#if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
+ d = (LONG_LONG)a * b;
+ if (FIXABLE(d)) return LONG2FIX(d);
+ return rb_ll2inum(d);
+#else
+ if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b))
+ return LONG2FIX(a*b);
c = a * b;
r = LONG2FIX(c);
+ if (a == 0) return x;
if (FIX2LONG(r) != c || c/a != b) {
r = rb_big_mul(rb_int2big(a), rb_int2big(b));
}
return r;
+#endif
}
- if (TYPE(y) == T_FLOAT) {
- return rb_float_new((double)FIX2LONG(x) * RFLOAT(y)->value);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return rb_big_mul(y, x);
+ case T_FLOAT:
+ return DBL2NUM((double)FIX2LONG(x) * RFLOAT_VALUE(y));
+ default:
+ return rb_num_coerce_bin(x, y, '*');
}
- return rb_num_coerce_bin(x, y);
}
static void
-fixdivmod(x, y, divp, modp)
- long x, y;
- long *divp, *modp;
+fixdivmod(long x, long y, long *divp, long *modp)
{
long div, mod;
@@ -2092,63 +2383,113 @@ fixdivmod(x, y, divp, modp)
if (modp) *modp = mod;
}
+VALUE rb_big_fdiv(VALUE x, VALUE y);
+
/*
* call-seq:
- * fix.quo(numeric) => float
- *
+ * fix.fdiv(numeric) -> float
+ *
* Returns the floating point result of dividing <i>fix</i> by
* <i>numeric</i>.
- *
- * 654321.quo(13731) #=> 47.6528293642124
- * 654321.quo(13731.24) #=> 47.6519964693647
- *
+ *
+ * 654321.fdiv(13731) #=> 47.6528293642124
+ * 654321.fdiv(13731.24) #=> 47.6519964693647
+ *
*/
static VALUE
-fix_quo(x, y)
- VALUE x, y;
+fix_fdiv(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- return rb_float_new((double)FIX2LONG(x) / (double)FIX2LONG(y));
+ return DBL2NUM((double)FIX2LONG(x) / (double)FIX2LONG(y));
+ }
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return rb_big_fdiv(rb_int2big(FIX2LONG(x)), y);
+ case T_FLOAT:
+ return DBL2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
+ default:
+ return rb_num_coerce_bin(x, y, rb_intern("fdiv"));
+ }
+}
+
+VALUE rb_rational_reciprocal(VALUE x);
+
+static VALUE
+fix_divide(VALUE x, VALUE y, ID op)
+{
+ if (FIXNUM_P(y)) {
+ long div;
+
+ fixdivmod(FIX2LONG(x), FIX2LONG(y), &div, 0);
+ return LONG2NUM(div);
+ }
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ x = rb_int2big(FIX2LONG(x));
+ return rb_big_div(x, y);
+ case T_FLOAT:
+ {
+ double div;
+
+ if (op == '/') {
+ div = (double)FIX2LONG(x) / RFLOAT_VALUE(y);
+ return DBL2NUM(div);
+ }
+ else {
+ if (RFLOAT_VALUE(y) == 0) rb_num_zerodiv();
+ div = (double)FIX2LONG(x) / RFLOAT_VALUE(y);
+ return rb_dbl2big(floor(div));
+ }
+ }
+ case T_RATIONAL:
+ if (op == '/' && FIX2LONG(x) == 1)
+ return rb_rational_reciprocal(y);
+ /* fall through */
+ default:
+ return rb_num_coerce_bin(x, y, op);
}
- return rb_num_coerce_bin(x, y);
}
/*
* call-seq:
- * fix / numeric => numeric_result
- * fix.div(numeric) => numeric_result
+ * fix / numeric -> numeric_result
*
* Performs division: the class of the resulting object depends on
- * the class of <code>numeric</code> and on the magnitude of the
+ * the class of <code>numeric</code> and on the magnitude of the
* result.
*/
static VALUE
-fix_div(x, y)
- VALUE x, y;
+fix_div(VALUE x, VALUE y)
{
- if (FIXNUM_P(y)) {
- long div;
+ return fix_divide(x, y, '/');
+}
- fixdivmod(FIX2LONG(x), FIX2LONG(y), &div, 0);
- return LONG2NUM(div);
- }
- return rb_num_coerce_bin(x, y);
+/*
+ * call-seq:
+ * fix.div(numeric) -> integer
+ *
+ * Performs integer division: returns integer value.
+ */
+
+static VALUE
+fix_idiv(VALUE x, VALUE y)
+{
+ return fix_divide(x, y, rb_intern("div"));
}
/*
* call-seq:
- * fix % other => Numeric
- * fix.modulo(other) => Numeric
+ * fix % other -> real
+ * fix.modulo(other) -> real
*
* Returns <code>fix</code> modulo <code>other</code>.
- * See <code>Numeric.divmod</code> for more information.
+ * See <code>numeric.divmod</code> for more information.
*/
static VALUE
-fix_mod(x, y)
- VALUE x, y;
+fix_mod(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
long mod;
@@ -2156,18 +2497,30 @@ fix_mod(x, y)
fixdivmod(FIX2LONG(x), FIX2LONG(y), 0, &mod);
return LONG2NUM(mod);
}
- return rb_num_coerce_bin(x, y);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ x = rb_int2big(FIX2LONG(x));
+ return rb_big_modulo(x, y);
+ case T_FLOAT:
+ {
+ double mod;
+
+ flodivmod((double)FIX2LONG(x), RFLOAT_VALUE(y), 0, &mod);
+ return DBL2NUM(mod);
+ }
+ default:
+ return rb_num_coerce_bin(x, y, '%');
+ }
}
/*
* call-seq:
- * fix.divmod(numeric) => array
- *
+ * fix.divmod(numeric) -> array
+ *
* See <code>Numeric#divmod</code>.
*/
static VALUE
-fix_divmod(x, y)
- VALUE x, y;
+fix_divmod(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
long div, mod;
@@ -2176,23 +2529,66 @@ fix_divmod(x, y)
return rb_assoc_new(LONG2NUM(div), LONG2NUM(mod));
}
- return rb_num_coerce_bin(x, y);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ x = rb_int2big(FIX2LONG(x));
+ return rb_big_divmod(x, y);
+ case T_FLOAT:
+ {
+ double div, mod;
+ volatile VALUE a, b;
+
+ flodivmod((double)FIX2LONG(x), RFLOAT_VALUE(y), &div, &mod);
+ a = dbl2ival(div);
+ b = DBL2NUM(mod);
+ return rb_assoc_new(a, b);
+ }
+ default:
+ return rb_num_coerce_bin(x, y, rb_intern("divmod"));
+ }
}
static VALUE
-int_even_p(VALUE num)
+int_pow(long x, unsigned long y)
{
- if (rb_funcall(num, '%', 1, INT2FIX(2)) == INT2FIX(0)) {
- return Qtrue;
- }
- return Qfalse;
+ int neg = x < 0;
+ long z = 1;
+
+ if (neg) x = -x;
+ if (y & 1)
+ z = x;
+ else
+ neg = 0;
+ y &= ~1;
+ do {
+ while (y % 2 == 0) {
+ if (!FIT_SQRT_LONG(x)) {
+ VALUE v;
+ bignum:
+ v = rb_big_pow(rb_int2big(x), LONG2NUM(y));
+ if (z != 1) v = rb_big_mul(rb_int2big(neg ? -z : z), v);
+ return v;
+ }
+ x = x * x;
+ y >>= 1;
+ }
+ {
+ volatile long xz = x * z;
+ if (!POSFIXABLE(xz) || xz / x != z) {
+ goto bignum;
+ }
+ z = xz;
+ }
+ } while (--y);
+ if (neg) z = -z;
+ return LONG2NUM(z);
}
/*
* call-seq:
- * fix ** other => Numeric
+ * fix ** numeric -> numeric_result
*
- * Raises <code>fix</code> to the <code>other</code> power, which may
+ * Raises <code>fix</code> to the <code>numeric</code> power, which may
* be negative or fractional.
*
* 2 ** 3 #=> 8
@@ -2201,33 +2597,37 @@ int_even_p(VALUE num)
*/
static VALUE
-fix_pow(x, y)
- VALUE x, y;
+fix_pow(VALUE x, VALUE y)
{
long a = FIX2LONG(x);
if (FIXNUM_P(y)) {
- long b;
+ long b = FIX2LONG(y);
+
+ if (b < 0)
+ return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
- b = FIX2LONG(y);
if (b == 0) return INT2FIX(1);
if (b == 1) return x;
- a = FIX2LONG(x);
- if (a == 0) return INT2FIX(0);
+ if (a == 0) {
+ if (b > 0) return INT2FIX(0);
+ return DBL2NUM(INFINITY);
+ }
if (a == 1) return INT2FIX(1);
if (a == -1) {
if (b % 2 == 0)
return INT2FIX(1);
- else
+ else
return INT2FIX(-1);
}
- if (b > 0) {
- return rb_big_pow(rb_int2big(a), y);
- }
- return rb_float_new(pow((double)a, (double)b));
+ return int_pow(a, b);
}
switch (TYPE(y)) {
case T_BIGNUM:
+
+ if (rb_funcall(y, '<', 1, INT2FIX(0)))
+ return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+
if (a == 0) return INT2FIX(0);
if (a == 1) return INT2FIX(1);
if (a == -1) {
@@ -2237,17 +2637,25 @@ fix_pow(x, y)
x = rb_int2big(FIX2LONG(x));
return rb_big_pow(x, y);
case T_FLOAT:
- if (a == 0) return rb_float_new(0.0);
- if (a == 1) return rb_float_new(1.0);
- return rb_float_new(pow((double)a, RFLOAT(y)->value));
+ if (RFLOAT_VALUE(y) == 0.0) return DBL2NUM(1.0);
+ if (a == 0) {
+ return DBL2NUM(RFLOAT_VALUE(y) < 0 ? INFINITY : 0.0);
+ }
+ if (a == 1) return DBL2NUM(1.0);
+ {
+ double dy = RFLOAT_VALUE(y);
+ if (a < 0 && dy != round(dy))
+ return rb_funcall(rb_complex_raw1(x), rb_intern("**"), 1, y);
+ return DBL2NUM(pow((double)a, dy));
+ }
default:
- return rb_num_coerce_bin(x, y);
+ return rb_num_coerce_bin(x, y, rb_intern("**"));
}
}
/*
* call-seq:
- * fix == other
+ * fix == other -> true or false
*
* Return <code>true</code> if <code>fix</code> equals <code>other</code>
* numerically.
@@ -2257,144 +2665,157 @@ fix_pow(x, y)
*/
static VALUE
-fix_equal(x, y)
- VALUE x, y;
+fix_equal(VALUE x, VALUE y)
{
- if (FIXNUM_P(y)) {
- return (FIX2LONG(x) == FIX2LONG(y))?Qtrue:Qfalse;
- }
- else {
+ if (x == y) return Qtrue;
+ if (FIXNUM_P(y)) return Qfalse;
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return rb_big_eq(y, x);
+ case T_FLOAT:
+ return (double)FIX2LONG(x) == RFLOAT_VALUE(y) ? Qtrue : Qfalse;
+ default:
return num_equal(x, y);
}
}
/*
* call-seq:
- * fix <=> numeric => -1, 0, +1
- *
- * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
- * less than, equal to, or greater than <i>numeric</i>. This is the
- * basis for the tests in <code>Comparable</code>.
+ * fix <=> numeric -> -1, 0, +1 or nil
+ *
+ * Comparison---Returns -1, 0, +1 or nil depending on whether
+ * <i>fix</i> is less than, equal to, or greater than
+ * <i>numeric</i>. This is the basis for the tests in
+ * <code>Comparable</code>.
*/
static VALUE
-fix_cmp(x, y)
- VALUE x, y;
+fix_cmp(VALUE x, VALUE y)
{
+ if (x == y) return INT2FIX(0);
if (FIXNUM_P(y)) {
- long a = FIX2LONG(x), b = FIX2LONG(y);
-
- if (a == b) return INT2FIX(0);
- if (a > b) return INT2FIX(1);
+ if (FIX2LONG(x) > FIX2LONG(y)) return INT2FIX(1);
return INT2FIX(-1);
}
- else {
- return rb_num_coerce_cmp(x, y);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return rb_big_cmp(rb_int2big(FIX2LONG(x)), y);
+ case T_FLOAT:
+ return rb_dbl_cmp((double)FIX2LONG(x), RFLOAT_VALUE(y));
+ default:
+ return rb_num_coerce_cmp(x, y, rb_intern("<=>"));
}
}
/*
* call-seq:
- * fix > other => true or false
+ * fix > real -> true or false
*
* Returns <code>true</code> if the value of <code>fix</code> is
- * greater than that of <code>other</code>.
+ * greater than that of <code>real</code>.
*/
static VALUE
-fix_gt(x, y)
- VALUE x, y;
+fix_gt(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- long a = FIX2LONG(x), b = FIX2LONG(y);
-
- if (a > b) return Qtrue;
+ if (FIX2LONG(x) > FIX2LONG(y)) return Qtrue;
return Qfalse;
}
- else {
- return rb_num_coerce_relop(x, y);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) > 0 ? Qtrue : Qfalse;
+ case T_FLOAT:
+ return (double)FIX2LONG(x) > RFLOAT_VALUE(y) ? Qtrue : Qfalse;
+ default:
+ return rb_num_coerce_relop(x, y, '>');
}
}
/*
* call-seq:
- * fix >= other => true or false
+ * fix >= real -> true or false
*
* Returns <code>true</code> if the value of <code>fix</code> is
- * greater than or equal to that of <code>other</code>.
+ * greater than or equal to that of <code>real</code>.
*/
static VALUE
-fix_ge(x, y)
- VALUE x, y;
+fix_ge(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- long a = FIX2LONG(x), b = FIX2LONG(y);
-
- if (a >= b) return Qtrue;
+ if (FIX2LONG(x) >= FIX2LONG(y)) return Qtrue;
return Qfalse;
}
- else {
- return rb_num_coerce_relop(x, y);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) >= 0 ? Qtrue : Qfalse;
+ case T_FLOAT:
+ return (double)FIX2LONG(x) >= RFLOAT_VALUE(y) ? Qtrue : Qfalse;
+ default:
+ return rb_num_coerce_relop(x, y, rb_intern(">="));
}
}
/*
* call-seq:
- * fix < other => true or false
+ * fix < real -> true or false
*
* Returns <code>true</code> if the value of <code>fix</code> is
- * less than that of <code>other</code>.
+ * less than that of <code>real</code>.
*/
static VALUE
-fix_lt(x, y)
- VALUE x, y;
+fix_lt(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- long a = FIX2LONG(x), b = FIX2LONG(y);
-
- if (a < b) return Qtrue;
+ if (FIX2LONG(x) < FIX2LONG(y)) return Qtrue;
return Qfalse;
}
- else {
- return rb_num_coerce_relop(x, y);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) < 0 ? Qtrue : Qfalse;
+ case T_FLOAT:
+ return (double)FIX2LONG(x) < RFLOAT_VALUE(y) ? Qtrue : Qfalse;
+ default:
+ return rb_num_coerce_relop(x, y, '<');
}
}
/*
* call-seq:
- * fix <= other => true or false
+ * fix <= real -> true or false
*
* Returns <code>true</code> if the value of <code>fix</code> is
- * less thanor equal to that of <code>other</code>.
+ * less than or equal to that of <code>real</code>.
*/
static VALUE
-fix_le(x, y)
- VALUE x, y;
+fix_le(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- long a = FIX2LONG(x), b = FIX2LONG(y);
-
- if (a <= b) return Qtrue;
+ if (FIX2LONG(x) <= FIX2LONG(y)) return Qtrue;
return Qfalse;
}
- else {
- return rb_num_coerce_relop(x, y);
+ switch (TYPE(y)) {
+ case T_BIGNUM:
+ return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) <= 0 ? Qtrue : Qfalse;
+ case T_FLOAT:
+ return (double)FIX2LONG(x) <= RFLOAT_VALUE(y) ? Qtrue : Qfalse;
+ default:
+ return rb_num_coerce_relop(x, y, rb_intern("<="));
}
}
/*
* call-seq:
- * ~fix => integer
+ * ~fix -> integer
*
* One's complement: returns a number where each bit is flipped.
*/
static VALUE
-fix_rev(num)
- VALUE num;
+fix_rev(VALUE num)
{
long val = FIX2LONG(num);
@@ -2402,79 +2823,87 @@ fix_rev(num)
return LONG2NUM(val);
}
+static VALUE
+bit_coerce(VALUE x)
+{
+ while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) {
+ if (TYPE(x) == T_FLOAT) {
+ rb_raise(rb_eTypeError, "can't convert Float into Integer");
+ }
+ x = rb_to_int(x);
+ }
+ return x;
+}
+
/*
* call-seq:
- * fix & other => integer
+ * fix & integer -> integer_result
*
* Bitwise AND.
*/
static VALUE
-fix_and(x, y)
- VALUE x, y;
+fix_and(VALUE x, VALUE y)
{
long val;
- if (TYPE(y) == T_BIGNUM) {
+ if (!FIXNUM_P(y = bit_coerce(y))) {
return rb_big_and(y, x);
}
- val = FIX2LONG(x) & NUM2LONG(y);
+ val = FIX2LONG(x) & FIX2LONG(y);
return LONG2NUM(val);
}
/*
* call-seq:
- * fix | other => integer
+ * fix | integer -> integer_result
*
* Bitwise OR.
*/
static VALUE
-fix_or(x, y)
- VALUE x, y;
+fix_or(VALUE x, VALUE y)
{
long val;
- if (TYPE(y) == T_BIGNUM) {
+ if (!FIXNUM_P(y = bit_coerce(y))) {
return rb_big_or(y, x);
}
- val = FIX2LONG(x) | NUM2LONG(y);
+ val = FIX2LONG(x) | FIX2LONG(y);
return LONG2NUM(val);
}
/*
* call-seq:
- * fix ^ other => integer
+ * fix ^ integer -> integer_result
*
* Bitwise EXCLUSIVE OR.
*/
static VALUE
-fix_xor(x, y)
- VALUE x, y;
+fix_xor(VALUE x, VALUE y)
{
long val;
- if (TYPE(y) == T_BIGNUM) {
+ if (!FIXNUM_P(y = bit_coerce(y))) {
return rb_big_xor(y, x);
}
- val = FIX2LONG(x) ^ NUM2LONG(y);
+ val = FIX2LONG(x) ^ FIX2LONG(y);
return LONG2NUM(val);
}
-static VALUE fix_lshift _((long, unsigned long));
-static VALUE fix_rshift _((long, unsigned long));
+static VALUE fix_lshift(long, unsigned long);
+static VALUE fix_rshift(long, unsigned long);
/*
* call-seq:
- * fix << count => integer
+ * fix << count -> integer
*
* Shifts _fix_ left _count_ positions (right if _count_ is negative).
*/
static VALUE
-rb_fix_lshift(x, y)
- VALUE x, y;
+rb_fix_lshift(VALUE x, VALUE y)
{
long val, width;
@@ -2488,12 +2917,10 @@ rb_fix_lshift(x, y)
}
static VALUE
-fix_lshift(val, width)
- long val;
- unsigned long width;
+fix_lshift(long val, unsigned long width)
{
- if (width > (sizeof(VALUE)*CHAR_BIT-1)
- || ((unsigned long)val)>>(sizeof(VALUE)*CHAR_BIT-1-width) > 0) {
+ if (width > (SIZEOF_LONG*CHAR_BIT-1)
+ || ((unsigned long)val)>>(SIZEOF_LONG*CHAR_BIT-1-width) > 0) {
return rb_big_lshift(rb_int2big(val), ULONG2NUM(width));
}
val = val << width;
@@ -2502,14 +2929,13 @@ fix_lshift(val, width)
/*
* call-seq:
- * fix >> count => integer
+ * fix >> count -> integer
*
* Shifts _fix_ right _count_ positions (left if _count_ is negative).
*/
static VALUE
-rb_fix_rshift(x, y)
- VALUE x, y;
+rb_fix_rshift(VALUE x, VALUE y)
{
long i, val;
@@ -2536,39 +2962,39 @@ fix_rshift(long val, unsigned long i)
/*
* call-seq:
- * fix[n] => 0, 1
- *
+ * fix[n] -> 0, 1
+ *
* Bit Reference---Returns the <em>n</em>th bit in the binary
* representation of <i>fix</i>, where <i>fix</i>[0] is the least
* significant bit.
- *
+ *
* a = 0b11001100101010
* 30.downto(0) do |n| print a[n] end
- *
+ *
* <em>produces:</em>
- *
+ *
* 0000000000000000011001100101010
*/
static VALUE
-fix_aref(fix, idx)
- VALUE fix, idx;
+fix_aref(VALUE fix, VALUE idx)
{
long val = FIX2LONG(fix);
long i;
- if (TYPE(idx) == T_BIGNUM) {
+ idx = rb_to_int(idx);
+ if (!FIXNUM_P(idx)) {
idx = rb_big_norm(idx);
if (!FIXNUM_P(idx)) {
- if (!RBIGNUM(idx)->sign || val >= 0)
+ if (!RBIGNUM_SIGN(idx) || val >= 0)
return INT2FIX(0);
return INT2FIX(1);
}
}
- i = NUM2LONG(idx);
+ i = FIX2LONG(idx);
if (i < 0) return INT2FIX(0);
- if (sizeof(VALUE)*CHAR_BIT-1 < i) {
+ if (SIZEOF_LONG*CHAR_BIT-1 < i) {
if (val < 0) return INT2FIX(1);
return INT2FIX(0);
}
@@ -2579,37 +3005,36 @@ fix_aref(fix, idx)
/*
* call-seq:
- * fix.to_f -> float
- *
+ * fix.to_f -> float
+ *
* Converts <i>fix</i> to a <code>Float</code>.
- *
+ *
*/
static VALUE
-fix_to_f(num)
- VALUE num;
+fix_to_f(VALUE num)
{
double val;
val = (double)FIX2LONG(num);
- return rb_float_new(val);
+ return DBL2NUM(val);
}
/*
* call-seq:
- * fix.abs -> aFixnum
- *
+ * fix.abs -> integer
+ * fix.magnitude -> integer
+ *
* Returns the absolute value of <i>fix</i>.
- *
+ *
* -12345.abs #=> 12345
* 12345.abs #=> 12345
- *
+ *
*/
static VALUE
-fix_abs(fix)
- VALUE fix;
+fix_abs(VALUE fix)
{
long i = FIX2LONG(fix);
@@ -2618,93 +3043,47 @@ fix_abs(fix)
return LONG2NUM(i);
}
-/*
- * call-seq:
- * fix.id2name -> string or nil
- *
- * Returns the name of the object whose symbol id is <i>fix</i>. If
- * there is no symbol in the symbol table with this value, returns
- * <code>nil</code>. <code>id2name</code> has nothing to do with the
- * <code>Object.id</code> method. See also <code>Fixnum#to_sym</code>,
- * <code>String#intern</code>, and class <code>Symbol</code>.
- *
- * symbol = :@inst_var #=> :@inst_var
- * id = symbol.to_i #=> 9818
- * id.id2name #=> "@inst_var"
- */
-
-static VALUE
-fix_id2name(fix)
- VALUE fix;
-{
- char *name = rb_id2name(FIX2UINT(fix));
- if (name) return rb_str_new2(name);
- return Qnil;
-}
-
-
-/*
- * call-seq:
- * fix.to_sym -> aSymbol
- *
- * Returns the symbol whose integer value is <i>fix</i>. See also
- * <code>Fixnum#id2name</code>.
- *
- * fred = :fred.to_i
- * fred.id2name #=> "fred"
- * fred.to_sym #=> :fred
- */
-
-static VALUE
-fix_to_sym(fix)
- VALUE fix;
-{
- ID id = FIX2UINT(fix);
-
- if (rb_id2name(id)) {
- return ID2SYM(id);
- }
- return Qnil;
-}
/*
* call-seq:
- * fix.size -> fixnum
- *
+ * fix.size -> fixnum
+ *
* Returns the number of <em>bytes</em> in the machine representation
* of a <code>Fixnum</code>.
- *
+ *
* 1.size #=> 4
* -1.size #=> 4
* 2147483647.size #=> 4
*/
static VALUE
-fix_size(fix)
- VALUE fix;
+fix_size(VALUE fix)
{
return INT2FIX(sizeof(long));
}
/*
* call-seq:
- * int.upto(limit) {|i| block } => int
- *
+ * int.upto(limit) {|i| block } -> self
+ * int.upto(limit) -> an_enumerator
+ *
* Iterates <em>block</em>, passing in integer values from <i>int</i>
* up to and including <i>limit</i>.
- *
+ *
+ * If no block is given, an enumerator is returned instead.
+ *
* 5.upto(10) { |i| print i, " " }
- *
+ *
* <em>produces:</em>
- *
+ *
* 5 6 7 8 9 10
*/
static VALUE
-int_upto(from, to)
- VALUE from, to;
+int_upto(VALUE from, VALUE to)
{
+ RETURN_ENUMERATOR(from, 1, &to);
if (FIXNUM_P(from) && FIXNUM_P(to)) {
long i, end;
@@ -2727,23 +3106,26 @@ int_upto(from, to)
/*
* call-seq:
- * int.downto(limit) {|i| block } => int
- *
+ * int.downto(limit) {|i| block } -> self
+ * int.downto(limit) -> an_enumerator
+ *
* Iterates <em>block</em>, passing decreasing values from <i>int</i>
* down to and including <i>limit</i>.
- *
+ *
+ * If no block is given, an enumerator is returned instead.
+ *
* 5.downto(1) { |n| print n, ".. " }
* print " Liftoff!\n"
- *
+ *
* <em>produces:</em>
- *
+ *
* 5.. 4.. 3.. 2.. 1.. Liftoff!
*/
static VALUE
-int_downto(from, to)
- VALUE from, to;
+int_downto(VALUE from, VALUE to)
{
+ RETURN_ENUMERATOR(from, 1, &to);
if (FIXNUM_P(from) && FIXNUM_P(to)) {
long i, end;
@@ -2766,24 +3148,28 @@ int_downto(from, to)
/*
* call-seq:
- * int.times {|i| block } => int
- *
+ * int.times {|i| block } -> self
+ * int.times -> an_enumerator
+ *
* Iterates block <i>int</i> times, passing in values from zero to
* <i>int</i> - 1.
- *
+ *
+ * If no block is given, an enumerator is returned instead.
+ *
* 5.times do |i|
* print i, " "
* end
- *
+ *
* <em>produces:</em>
- *
+ *
* 0 1 2 3 4
*/
static VALUE
-int_dotimes(num)
- VALUE num;
+int_dotimes(VALUE num)
{
+ RETURN_ENUMERATOR(num, 0, 0);
+
if (FIXNUM_P(num)) {
long i, end;
@@ -2806,15 +3192,64 @@ int_dotimes(num)
/*
* call-seq:
- * fix.zero? => true or false
- *
+ * num.round([ndigits]) -> integer or float
+ *
+ * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
+ * Precision may be negative. Returns a floating point number when +ndigits+
+ * is positive, +self+ for zero, and round down for negative.
+ *
+ * 1.round #=> 1
+ * 1.round(2) #=> 1.0
+ * 15.round(-1) #=> 20
+ */
+
+static VALUE
+int_round(int argc, VALUE* argv, VALUE num)
+{
+ VALUE n, f, h, r;
+ int ndigits;
+
+ if (argc == 0) return num;
+ rb_scan_args(argc, argv, "1", &n);
+ ndigits = NUM2INT(n);
+ if (ndigits > 0) {
+ return rb_Float(num);
+ }
+ if (ndigits == 0) {
+ return num;
+ }
+ ndigits = -ndigits;
+ if (ndigits < 0) {
+ rb_raise(rb_eArgError, "ndigits out of range");
+ }
+ f = int_pow(10, ndigits);
+ if (FIXNUM_P(num) && FIXNUM_P(f)) {
+ SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
+ int neg = x < 0;
+ if (neg) x = -x;
+ x = (x + y / 2) / y * y;
+ if (neg) x = -x;
+ return LONG2NUM(x);
+ }
+ h = rb_funcall(f, '/', 1, INT2FIX(2));
+ r = rb_funcall(num, '%', 1, f);
+ n = rb_funcall(num, '-', 1, r);
+ if (!RTEST(rb_funcall(r, '<', 1, h))) {
+ n = rb_funcall(n, '+', 1, f);
+ }
+ return n;
+}
+
+/*
+ * call-seq:
+ * fix.zero? -> true or false
+ *
* Returns <code>true</code> if <i>fix</i> is zero.
- *
+ *
*/
static VALUE
-fix_zero_p(num)
- VALUE num;
+fix_zero_p(VALUE num)
{
if (FIX2LONG(num) == 0) {
return Qtrue;
@@ -2822,9 +3257,76 @@ fix_zero_p(num)
return Qfalse;
}
+/*
+ * call-seq:
+ * fix.odd? -> true or false
+ *
+ * Returns <code>true</code> if <i>fix</i> is an odd number.
+ */
+
+static VALUE
+fix_odd_p(VALUE num)
+{
+ if (num & 2) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+/*
+ * call-seq:
+ * fix.even? -> true or false
+ *
+ * Returns <code>true</code> if <i>fix</i> is an even number.
+ */
+
+static VALUE
+fix_even_p(VALUE num)
+{
+ if (num & 2) {
+ return Qfalse;
+ }
+ return Qtrue;
+}
+
+/*
+ * Document-class: ZeroDivisionError
+ *
+ * Raised when attempting to divide an integer by 0.
+ *
+ * 42 / 0
+ *
+ * <em>raises the exception:</em>
+ *
+ * ZeroDivisionError: divided by 0
+ *
+ * Note that only division by an exact 0 will raise that exception:
+ *
+ * 42 / 0.0 #=> Float::INFINITY
+ * 42 / -0.0 #=> -Float::INFINITY
+ * 0 / 0.0 #=> NaN
+ */
+
+/*
+ * Document-class: FloatDomainError
+ *
+ * Raised when attempting to convert special float values
+ * (in particular infinite or NaN)
+ * to numerical classes which don't support them.
+ *
+ * Float::INFINITY.to_r
+ *
+ * <em>raises the exception:</em>
+ *
+ * FloatDomainError: Infinity
+ */
+
void
-Init_Numeric()
+Init_Numeric(void)
{
+#undef rb_intern
+#define rb_intern(str) rb_intern_const(str)
+
#if defined(__FreeBSD__) && __FreeBSD__ < 4
/* allow divide by zero -- Inf */
fpsetmask(fpgetmask() & ~(FP_X_DZ|FP_X_INV|FP_X_OFL));
@@ -2848,25 +3350,30 @@ Init_Numeric()
rb_define_method(rb_cNumeric, "initialize_copy", num_init_copy, 1);
rb_define_method(rb_cNumeric, "coerce", num_coerce, 1);
+ rb_define_method(rb_cNumeric, "i", num_imaginary, 0);
rb_define_method(rb_cNumeric, "+@", num_uplus, 0);
rb_define_method(rb_cNumeric, "-@", num_uminus, 0);
rb_define_method(rb_cNumeric, "<=>", num_cmp, 1);
rb_define_method(rb_cNumeric, "eql?", num_eql, 1);
rb_define_method(rb_cNumeric, "quo", num_quo, 1);
+ rb_define_method(rb_cNumeric, "fdiv", num_fdiv, 1);
rb_define_method(rb_cNumeric, "div", num_div, 1);
rb_define_method(rb_cNumeric, "divmod", num_divmod, 1);
+ rb_define_method(rb_cNumeric, "%", num_modulo, 1);
rb_define_method(rb_cNumeric, "modulo", num_modulo, 1);
rb_define_method(rb_cNumeric, "remainder", num_remainder, 1);
rb_define_method(rb_cNumeric, "abs", num_abs, 0);
+ rb_define_method(rb_cNumeric, "magnitude", num_abs, 0);
rb_define_method(rb_cNumeric, "to_int", num_to_int, 0);
+ rb_define_method(rb_cNumeric, "real?", num_real_p, 0);
rb_define_method(rb_cNumeric, "integer?", num_int_p, 0);
rb_define_method(rb_cNumeric, "zero?", num_zero_p, 0);
rb_define_method(rb_cNumeric, "nonzero?", num_nonzero_p, 0);
rb_define_method(rb_cNumeric, "floor", num_floor, 0);
rb_define_method(rb_cNumeric, "ceil", num_ceil, 0);
- rb_define_method(rb_cNumeric, "round", num_round, 0);
+ rb_define_method(rb_cNumeric, "round", num_round, -1);
rb_define_method(rb_cNumeric, "truncate", num_truncate, 0);
rb_define_method(rb_cNumeric, "step", num_step, -1);
@@ -2875,45 +3382,44 @@ Init_Numeric()
rb_undef_method(CLASS_OF(rb_cInteger), "new");
rb_define_method(rb_cInteger, "integer?", int_int_p, 0);
+ rb_define_method(rb_cInteger, "odd?", int_odd_p, 0);
+ rb_define_method(rb_cInteger, "even?", int_even_p, 0);
rb_define_method(rb_cInteger, "upto", int_upto, 1);
rb_define_method(rb_cInteger, "downto", int_downto, 1);
rb_define_method(rb_cInteger, "times", int_dotimes, 0);
- rb_include_module(rb_cInteger, rb_mPrecision);
rb_define_method(rb_cInteger, "succ", int_succ, 0);
rb_define_method(rb_cInteger, "next", int_succ, 0);
- rb_define_method(rb_cInteger, "chr", int_chr, 0);
+ rb_define_method(rb_cInteger, "pred", int_pred, 0);
+ rb_define_method(rb_cInteger, "chr", int_chr, -1);
+ rb_define_method(rb_cInteger, "ord", int_ord, 0);
rb_define_method(rb_cInteger, "to_i", int_to_i, 0);
rb_define_method(rb_cInteger, "to_int", int_to_i, 0);
rb_define_method(rb_cInteger, "floor", int_to_i, 0);
rb_define_method(rb_cInteger, "ceil", int_to_i, 0);
- rb_define_method(rb_cInteger, "round", int_to_i, 0);
rb_define_method(rb_cInteger, "truncate", int_to_i, 0);
+ rb_define_method(rb_cInteger, "round", int_round, -1);
rb_cFixnum = rb_define_class("Fixnum", rb_cInteger);
- rb_include_module(rb_cFixnum, rb_mPrecision);
- rb_define_singleton_method(rb_cFixnum, "induced_from", rb_fix_induced_from, 1);
- rb_define_singleton_method(rb_cInteger, "induced_from", rb_int_induced_from, 1);
rb_define_method(rb_cFixnum, "to_s", fix_to_s, -1);
- rb_define_method(rb_cFixnum, "id2name", fix_id2name, 0);
- rb_define_method(rb_cFixnum, "to_sym", fix_to_sym, 0);
-
rb_define_method(rb_cFixnum, "-@", fix_uminus, 0);
rb_define_method(rb_cFixnum, "+", fix_plus, 1);
rb_define_method(rb_cFixnum, "-", fix_minus, 1);
rb_define_method(rb_cFixnum, "*", fix_mul, 1);
rb_define_method(rb_cFixnum, "/", fix_div, 1);
- rb_define_method(rb_cFixnum, "div", fix_div, 1);
+ rb_define_method(rb_cFixnum, "div", fix_idiv, 1);
rb_define_method(rb_cFixnum, "%", fix_mod, 1);
rb_define_method(rb_cFixnum, "modulo", fix_mod, 1);
rb_define_method(rb_cFixnum, "divmod", fix_divmod, 1);
- rb_define_method(rb_cFixnum, "quo", fix_quo, 1);
+ rb_define_method(rb_cFixnum, "fdiv", fix_fdiv, 1);
rb_define_method(rb_cFixnum, "**", fix_pow, 1);
rb_define_method(rb_cFixnum, "abs", fix_abs, 0);
+ rb_define_method(rb_cFixnum, "magnitude", fix_abs, 0);
rb_define_method(rb_cFixnum, "==", fix_equal, 1);
+ rb_define_method(rb_cFixnum, "===", fix_equal, 1);
rb_define_method(rb_cFixnum, "<=>", fix_cmp, 1);
rb_define_method(rb_cFixnum, ">", fix_gt, 1);
rb_define_method(rb_cFixnum, ">=", fix_ge, 1);
@@ -2932,15 +3438,15 @@ Init_Numeric()
rb_define_method(rb_cFixnum, "to_f", fix_to_f, 0);
rb_define_method(rb_cFixnum, "size", fix_size, 0);
rb_define_method(rb_cFixnum, "zero?", fix_zero_p, 0);
+ rb_define_method(rb_cFixnum, "odd?", fix_odd_p, 0);
+ rb_define_method(rb_cFixnum, "even?", fix_even_p, 0);
+ rb_define_method(rb_cFixnum, "succ", fix_succ, 0);
rb_cFloat = rb_define_class("Float", rb_cNumeric);
rb_undef_alloc_func(rb_cFloat);
rb_undef_method(CLASS_OF(rb_cFloat), "new");
- rb_define_singleton_method(rb_cFloat, "induced_from", rb_flo_induced_from, 1);
- rb_include_module(rb_cFloat, rb_mPrecision);
-
rb_define_const(rb_cFloat, "ROUNDS", INT2FIX(FLT_ROUNDS));
rb_define_const(rb_cFloat, "RADIX", INT2FIX(FLT_RADIX));
rb_define_const(rb_cFloat, "MANT_DIG", INT2FIX(DBL_MANT_DIG));
@@ -2949,9 +3455,11 @@ Init_Numeric()
rb_define_const(rb_cFloat, "MAX_EXP", INT2FIX(DBL_MAX_EXP));
rb_define_const(rb_cFloat, "MIN_10_EXP", INT2FIX(DBL_MIN_10_EXP));
rb_define_const(rb_cFloat, "MAX_10_EXP", INT2FIX(DBL_MAX_10_EXP));
- rb_define_const(rb_cFloat, "MIN", rb_float_new(DBL_MIN));
- rb_define_const(rb_cFloat, "MAX", rb_float_new(DBL_MAX));
- rb_define_const(rb_cFloat, "EPSILON", rb_float_new(DBL_EPSILON));
+ rb_define_const(rb_cFloat, "MIN", DBL2NUM(DBL_MIN));
+ rb_define_const(rb_cFloat, "MAX", DBL2NUM(DBL_MAX));
+ rb_define_const(rb_cFloat, "EPSILON", DBL2NUM(DBL_EPSILON));
+ rb_define_const(rb_cFloat, "INFINITY", DBL2NUM(INFINITY));
+ rb_define_const(rb_cFloat, "NAN", DBL2NUM(NAN));
rb_define_method(rb_cFloat, "to_s", flo_to_s, 0);
rb_define_method(rb_cFloat, "coerce", flo_coerce, 1);
@@ -2960,11 +3468,14 @@ Init_Numeric()
rb_define_method(rb_cFloat, "-", flo_minus, 1);
rb_define_method(rb_cFloat, "*", flo_mul, 1);
rb_define_method(rb_cFloat, "/", flo_div, 1);
+ rb_define_method(rb_cFloat, "quo", flo_quo, 1);
+ rb_define_method(rb_cFloat, "fdiv", flo_quo, 1);
rb_define_method(rb_cFloat, "%", flo_mod, 1);
rb_define_method(rb_cFloat, "modulo", flo_mod, 1);
rb_define_method(rb_cFloat, "divmod", flo_divmod, 1);
rb_define_method(rb_cFloat, "**", flo_pow, 1);
rb_define_method(rb_cFloat, "==", flo_eq, 1);
+ rb_define_method(rb_cFloat, "===", flo_eq, 1);
rb_define_method(rb_cFloat, "<=>", flo_cmp, 1);
rb_define_method(rb_cFloat, ">", flo_gt, 1);
rb_define_method(rb_cFloat, ">=", flo_ge, 1);
@@ -2974,13 +3485,14 @@ Init_Numeric()
rb_define_method(rb_cFloat, "hash", flo_hash, 0);
rb_define_method(rb_cFloat, "to_f", flo_to_f, 0);
rb_define_method(rb_cFloat, "abs", flo_abs, 0);
+ rb_define_method(rb_cFloat, "magnitude", flo_abs, 0);
rb_define_method(rb_cFloat, "zero?", flo_zero_p, 0);
rb_define_method(rb_cFloat, "to_i", flo_truncate, 0);
rb_define_method(rb_cFloat, "to_int", flo_truncate, 0);
rb_define_method(rb_cFloat, "floor", flo_floor, 0);
rb_define_method(rb_cFloat, "ceil", flo_ceil, 0);
- rb_define_method(rb_cFloat, "round", flo_round, 0);
+ rb_define_method(rb_cFloat, "round", flo_round, -1);
rb_define_method(rb_cFloat, "truncate", flo_truncate, 0);
rb_define_method(rb_cFloat, "nan?", flo_is_nan_p, 0);