summaryrefslogtreecommitdiff
path: root/numeric.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2021-07-26 10:45:56 -0700
committerJeremy Evans <code@jeremyevans.net>2021-07-27 11:00:45 -0700
commit35e467080ca35a9a129e95f802f102c3bc0a81b3 (patch)
tree162489bbf3dd40c61af61f0fe2f452205957126b /numeric.c
parent338b604b3216b633d0fc897a915168104f20a514 (diff)
Make Float#floor with ndigits argument handle error
The previous implementation could result in a returned float that is 1/(10**ndigits) too low. First try adding one before dividing, and if that results in a value that is greater than the initial number, then try the original calculation. Spec added for ciel, but the issue doesn't appear to affect ciel, at least not for the same number. If the issue does effect ciel, a similar fix could probably work for it. Fixes [Bug #18018]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4681
Diffstat (limited to 'numeric.c')
-rw-r--r--numeric.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/numeric.c b/numeric.c
index 345067c6a5..5564a6eceb 100644
--- a/numeric.c
+++ b/numeric.c
@@ -1829,20 +1829,24 @@ flo_prev_float(VALUE vx)
VALUE
rb_float_floor(VALUE num, int ndigits)
{
- double number, f;
+ double number;
number = RFLOAT_VALUE(num);
if (number == 0.0) {
return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0);
}
if (ndigits > 0) {
int binexp;
+ double f, mul, res;
frexp(number, &binexp);
if (float_round_overflow(ndigits, binexp)) return num;
if (number > 0.0 && float_round_underflow(ndigits, binexp))
return DBL2NUM(0.0);
f = pow(10, ndigits);
- f = floor(number * f) / f;
- return DBL2NUM(f);
+ mul = floor(number * f);
+ res = (mul + 1) / f;
+ if (res > number)
+ res = mul / f;
+ return DBL2NUM(res);
}
else {
num = dbl2ival(floor(number));