diff options
author | Kenta Murata <3959+mrkn@users.noreply.github.com> | 2022-12-26 21:02:47 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-26 21:02:47 +0900 |
commit | 9f2378959e5c5b5c39c9993f1a84e5304ff113d6 (patch) | |
tree | be3582344869f036ed52b0c0a96e24d7c5655f9d /numeric.c | |
parent | bb60e4615f49a4dbc4f0eb776c8773feabb1a66f (diff) |
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.
Notes
Notes:
Merged-By: mrkn <mrkn@ruby-lang.org>
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 26 |
1 files changed, 16 insertions, 10 deletions
@@ -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); |