зеркало из https://github.com/github/ruby.git
numeric.c: Fix round_half_even for specific values (#7023)
Handle the integert and the float parts separately in round_half_even to prevent error occursions in floating point calculation.
This commit is contained in:
Родитель
bb60e4615f
Коммит
9f2378959e
26
numeric.c
26
numeric.c
|
@ -144,31 +144,37 @@ round_half_down(double x, double s)
|
|||
static double
|
||||
round_half_even(double x, double s)
|
||||
{
|
||||
double f, d, xs = x * s;
|
||||
double u, v, us, vs, f, d, uf;
|
||||
|
||||
v = modf(x, &u);
|
||||
us = u * s;
|
||||
vs = v * s;
|
||||
|
||||
if (x > 0.0) {
|
||||
f = floor(xs);
|
||||
d = xs - f;
|
||||
f = floor(vs);
|
||||
uf = us + f;
|
||||
d = vs - f;
|
||||
if (d > 0.5)
|
||||
d = 1.0;
|
||||
else if (d == 0.5 || ((double)((f + 0.5) / s) <= x))
|
||||
d = fmod(f, 2.0);
|
||||
else if (d == 0.5 || ((double)((uf + 0.5) / s) <= x))
|
||||
d = fmod(uf, 2.0);
|
||||
else
|
||||
d = 0.0;
|
||||
x = f + d;
|
||||
}
|
||||
else if (x < 0.0) {
|
||||
f = ceil(xs);
|
||||
d = f - xs;
|
||||
f = ceil(vs);
|
||||
uf = us + f;
|
||||
d = f - vs;
|
||||
if (d > 0.5)
|
||||
d = 1.0;
|
||||
else if (d == 0.5 || ((double)((f - 0.5) / s) >= x))
|
||||
d = fmod(-f, 2.0);
|
||||
else if (d == 0.5 || ((double)((uf - 0.5) / s) >= x))
|
||||
d = fmod(-uf, 2.0);
|
||||
else
|
||||
d = 0.0;
|
||||
x = f - d;
|
||||
}
|
||||
return x;
|
||||
return us + x;
|
||||
}
|
||||
|
||||
static VALUE fix_lshift(long, unsigned long);
|
||||
|
|
|
@ -136,7 +136,7 @@ describe "Float#round" do
|
|||
-4.809999999999999.round(5, half: :even).should eql(-4.81)
|
||||
end
|
||||
|
||||
ruby_bug "", ""..."3.4" do
|
||||
ruby_bug "", ""..."3.3" do
|
||||
# These numbers are neighbouring floating point numbers round a
|
||||
# precise value. They test that the rounding modes work correctly
|
||||
# round that value and precision is not lost which might cause
|
||||
|
|
|
@ -486,6 +486,17 @@ class TestFloat < Test::Unit::TestCase
|
|||
assert_equal(-1.26, -1.255.round(2))
|
||||
end
|
||||
|
||||
def test_round_half_even_with_precision
|
||||
assert_equal(767573.18759, 767573.1875850001.round(5, half: :even))
|
||||
assert_equal(767573.18758, 767573.187585.round(5, half: :even))
|
||||
assert_equal(767573.18758, 767573.1875849998.round(5, half: :even))
|
||||
assert_equal(767573.18758, 767573.187575.round(5, half: :even))
|
||||
assert_equal(-767573.18759, -767573.1875850001.round(5, half: :even))
|
||||
assert_equal(-767573.18758, -767573.187585.round(5, half: :even))
|
||||
assert_equal(-767573.18758, -767573.1875849998.round(5, half: :even))
|
||||
assert_equal(-767573.18758, -767573.187575.round(5, half: :even))
|
||||
end
|
||||
|
||||
def test_floor_with_precision
|
||||
assert_equal(+0.0, +0.001.floor(1))
|
||||
assert_equal(-0.1, -0.001.floor(1))
|
||||
|
|
Загрузка…
Ссылка в новой задаче