* bignum.c (rb_big_fdiv): checks whether the given second argument
can be converted to float properly. * numeric.c (fix_fdiv): calls rb_big_fdiv when the given second argument is a bignum. * rational.c (nurat_fdiv): should calculate Float(x/y), not Float(x)/Float(y). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23726 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
bbd2b5e9bd
commit
b6849b2502
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
|||||||
|
Wed Jun 17 21:25:54 2009 Tadayoshi Funaba <tadf@dotrb.org>
|
||||||
|
|
||||||
|
* bignum.c (rb_big_fdiv): checks whether the given second argument
|
||||||
|
can be converted to float properly.
|
||||||
|
|
||||||
|
* numeric.c (fix_fdiv): calls rb_big_fdiv when the given second
|
||||||
|
argument is a bignum.
|
||||||
|
|
||||||
|
* rational.c (nurat_fdiv): should calculate Float(x/y), not
|
||||||
|
Float(x)/Float(y).
|
||||||
|
|
||||||
Wed Jun 17 16:57:40 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
|
Wed Jun 17 16:57:40 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||||
|
|
||||||
* load.c (rb_f_require): RDoc updated. a patch from Run Paint Run
|
* load.c (rb_f_require): RDoc updated. a patch from Run Paint Run
|
||||||
|
103
bignum.c
103
bignum.c
@ -2385,6 +2385,52 @@ big_shift(VALUE x, long n)
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
big_fdiv(VALUE x, VALUE y)
|
||||||
|
{
|
||||||
|
#define DBL_BIGDIG ((DBL_MANT_DIG + BITSPERDIG) / BITSPERDIG)
|
||||||
|
VALUE z;
|
||||||
|
long l, ex, ey;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bigtrunc(x);
|
||||||
|
l = RBIGNUM_LEN(x) - 1;
|
||||||
|
ex = l * BITSPERDIG;
|
||||||
|
ex += bdigbitsize(BDIGITS(x)[l]);
|
||||||
|
ex -= 2 * DBL_BIGDIG * BITSPERDIG;
|
||||||
|
if (ex) x = big_shift(x, ex);
|
||||||
|
|
||||||
|
switch (TYPE(y)) {
|
||||||
|
case T_FIXNUM:
|
||||||
|
y = rb_int2big(FIX2LONG(y));
|
||||||
|
case T_BIGNUM: {
|
||||||
|
bigtrunc(y);
|
||||||
|
l = RBIGNUM_LEN(y) - 1;
|
||||||
|
ey = l * BITSPERDIG;
|
||||||
|
ey += bdigbitsize(BDIGITS(y)[l]);
|
||||||
|
ey -= DBL_BIGDIG * BITSPERDIG;
|
||||||
|
if (ey) y = big_shift(y, ey);
|
||||||
|
bignum:
|
||||||
|
bigdivrem(x, y, &z, 0);
|
||||||
|
l = ex - ey;
|
||||||
|
#if SIZEOF_LONG > SIZEOF_INT
|
||||||
|
{
|
||||||
|
/* Visual C++ can't be here */
|
||||||
|
if (l > INT_MAX) return DBL2NUM(ruby_div0(1.0));
|
||||||
|
if (l < INT_MIN) return DBL2NUM(0.0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return DBL2NUM(ldexp(big2dbl(z), (int)l));
|
||||||
|
}
|
||||||
|
case T_FLOAT:
|
||||||
|
y = dbl2big(ldexp(frexp(RFLOAT_VALUE(y), &i), DBL_MANT_DIG));
|
||||||
|
ey = i - DBL_MANT_DIG;
|
||||||
|
goto bignum;
|
||||||
|
}
|
||||||
|
rb_bug("big_fdiv");
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* big.fdiv(numeric) -> float
|
* big.fdiv(numeric) -> float
|
||||||
@ -2397,65 +2443,32 @@ big_shift(VALUE x, long n)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
|
||||||
|
VALUE
|
||||||
rb_big_fdiv(VALUE x, VALUE y)
|
rb_big_fdiv(VALUE x, VALUE y)
|
||||||
{
|
{
|
||||||
double dx = big2dbl(x);
|
double dx, dy;
|
||||||
double dy;
|
|
||||||
|
|
||||||
if (isinf(dx)) {
|
dx = big2dbl(x);
|
||||||
#define DBL_BIGDIG ((DBL_MANT_DIG + BITSPERDIG) / BITSPERDIG)
|
|
||||||
VALUE z;
|
|
||||||
long l, ex, ey;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
bigtrunc(x);
|
|
||||||
l = RBIGNUM_LEN(x) - 1;
|
|
||||||
ex = l * BITSPERDIG;
|
|
||||||
ex += bdigbitsize(BDIGITS(x)[l]);
|
|
||||||
ex -= 2 * DBL_BIGDIG * BITSPERDIG;
|
|
||||||
if (ex) x = big_shift(x, ex);
|
|
||||||
|
|
||||||
switch (TYPE(y)) {
|
|
||||||
case T_FIXNUM:
|
|
||||||
y = rb_int2big(FIX2LONG(y));
|
|
||||||
case T_BIGNUM: {
|
|
||||||
bigtrunc(y);
|
|
||||||
l = RBIGNUM_LEN(y) - 1;
|
|
||||||
ey = l * BITSPERDIG;
|
|
||||||
ey += bdigbitsize(BDIGITS(y)[l]);
|
|
||||||
ey -= DBL_BIGDIG * BITSPERDIG;
|
|
||||||
if (ey) y = big_shift(y, ey);
|
|
||||||
bignum:
|
|
||||||
bigdivrem(x, y, &z, 0);
|
|
||||||
l = ex - ey;
|
|
||||||
#if SIZEOF_LONG > SIZEOF_INT
|
|
||||||
{
|
|
||||||
/* Visual C++ can't be here */
|
|
||||||
if (l > INT_MAX) return DBL2NUM(ruby_div0(1.0));
|
|
||||||
if (l < INT_MIN) return DBL2NUM(0.0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return DBL2NUM(ldexp(big2dbl(z), (int)l));
|
|
||||||
}
|
|
||||||
case T_FLOAT:
|
|
||||||
if (isnan(RFLOAT_VALUE(y))) return y;
|
|
||||||
y = dbl2big(ldexp(frexp(RFLOAT_VALUE(y), &i), DBL_MANT_DIG));
|
|
||||||
ey = i - DBL_MANT_DIG;
|
|
||||||
goto bignum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (TYPE(y)) {
|
switch (TYPE(y)) {
|
||||||
case T_FIXNUM:
|
case T_FIXNUM:
|
||||||
dy = (double)FIX2LONG(y);
|
dy = (double)FIX2LONG(y);
|
||||||
|
if (isinf(dx))
|
||||||
|
return big_fdiv(x, y);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_BIGNUM:
|
case T_BIGNUM:
|
||||||
dy = rb_big2dbl(y);
|
dy = rb_big2dbl(y);
|
||||||
|
if (isinf(dx) || isinf(dy))
|
||||||
|
return big_fdiv(x, y);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FLOAT:
|
case T_FLOAT:
|
||||||
dy = RFLOAT_VALUE(y);
|
dy = RFLOAT_VALUE(y);
|
||||||
|
if (isnan(dy))
|
||||||
|
return y;
|
||||||
|
if (isinf(dx))
|
||||||
|
return big_fdiv(x, y);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2269,6 +2269,8 @@ fixdivmod(long x, long y, long *divp, long *modp)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
VALUE rb_big_fdiv(VALUE x, VALUE y);
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
fix_fdiv(VALUE x, VALUE y)
|
fix_fdiv(VALUE x, VALUE y)
|
||||||
{
|
{
|
||||||
@ -2277,7 +2279,7 @@ fix_fdiv(VALUE x, VALUE y)
|
|||||||
}
|
}
|
||||||
switch (TYPE(y)) {
|
switch (TYPE(y)) {
|
||||||
case T_BIGNUM:
|
case T_BIGNUM:
|
||||||
return DBL2NUM((double)FIX2LONG(x) / rb_big2dbl(y));
|
return rb_big_fdiv(rb_int2big(FIX2LONG(x)), y);
|
||||||
case T_FLOAT:
|
case T_FLOAT:
|
||||||
return DBL2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
|
return DBL2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
|
||||||
default:
|
default:
|
||||||
|
@ -769,7 +769,7 @@ nurat_div(VALUE self, VALUE other)
|
|||||||
static VALUE
|
static VALUE
|
||||||
nurat_fdiv(VALUE self, VALUE other)
|
nurat_fdiv(VALUE self, VALUE other)
|
||||||
{
|
{
|
||||||
return f_div(f_to_f(self), other);
|
return f_to_f(f_div(self, other));
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -4,6 +4,9 @@ class TestBignum < Test::Unit::TestCase
|
|||||||
def setup
|
def setup
|
||||||
@verbose = $VERBOSE
|
@verbose = $VERBOSE
|
||||||
$VERBOSE = nil
|
$VERBOSE = nil
|
||||||
|
@fmax = Float::MAX.to_i
|
||||||
|
@fmax2 = @fmax * 2
|
||||||
|
@big = (1 << 63) - 1
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
@ -395,4 +398,19 @@ class TestBignum < Test::Unit::TestCase
|
|||||||
e = assert_raise(RangeError) {(1 << big).to_s}
|
e = assert_raise(RangeError) {(1 << big).to_s}
|
||||||
assert_match(/too big to convert/, e.message)
|
assert_match(/too big to convert/, e.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_fix_fdiv
|
||||||
|
assert_not_equal(0, 1.fdiv(@fmax2))
|
||||||
|
assert_in_delta(0.5, 1.fdiv(@fmax2) * @fmax, 0.01)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_big_fdiv
|
||||||
|
assert_equal(1, @big.fdiv(@big))
|
||||||
|
assert_not_equal(0, @big.fdiv(@fmax2))
|
||||||
|
assert_not_equal(0, @fmax2.fdiv(@big))
|
||||||
|
assert_not_equal(0, @fmax2.fdiv(@fmax2))
|
||||||
|
assert_in_delta(0.5, @fmax.fdiv(@fmax2), 0.01)
|
||||||
|
assert_in_delta(1.0, @fmax2.fdiv(@fmax2), 0.01)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user