зеркало из https://github.com/github/ruby.git
[Bug #17037] Improve accuracy of division near precision limits
When dividing near the precision limit of `double`, use Bignum division to get rid of rounding errors.
This commit is contained in:
Родитель
79eb75a8dd
Коммит
8e93bf8e1f
10
numeric.c
10
numeric.c
|
@ -4096,7 +4096,13 @@ static double
|
|||
fix_fdiv_double(VALUE x, VALUE y)
|
||||
{
|
||||
if (FIXNUM_P(y)) {
|
||||
return double_div_double(FIX2LONG(x), FIX2LONG(y));
|
||||
long iy = FIX2LONG(y);
|
||||
#if SIZEOF_LONG * CHAR_BIT > DBL_MANT_DIG
|
||||
if ((iy < 0 ? -iy : iy) >= (1L << DBL_MANT_DIG)) {
|
||||
return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), rb_int2big(iy));
|
||||
}
|
||||
#endif
|
||||
return double_div_double(FIX2LONG(x), iy);
|
||||
}
|
||||
else if (RB_BIGNUM_TYPE_P(y)) {
|
||||
return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), y);
|
||||
|
@ -4114,7 +4120,7 @@ rb_int_fdiv_double(VALUE x, VALUE y)
|
|||
{
|
||||
if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) {
|
||||
VALUE gcd = rb_gcd(x, y);
|
||||
if (!FIXNUM_ZERO_P(gcd)) {
|
||||
if (!FIXNUM_ZERO_P(gcd) && gcd != INT2FIX(1)) {
|
||||
x = rb_int_idiv(x, gcd);
|
||||
y = rb_int_idiv(y, gcd);
|
||||
}
|
||||
|
|
|
@ -704,6 +704,14 @@ class TestInteger < Test::Unit::TestCase
|
|||
def test_fdiv
|
||||
assert_equal(1.0, 1.fdiv(1))
|
||||
assert_equal(0.5, 1.fdiv(2))
|
||||
|
||||
m = 50 << Float::MANT_DIG
|
||||
prev = 1.0
|
||||
(1..100).each do |i|
|
||||
val = (m + i).fdiv(m)
|
||||
assert_operator val, :>=, prev, "1+epsilon*(#{i}/100)"
|
||||
prev = val
|
||||
end
|
||||
end
|
||||
|
||||
def test_obj_fdiv
|
||||
|
|
Загрузка…
Ссылка в новой задаче