diff options
author | Jeremy Evans <[email protected]> | 2021-07-26 10:45:56 -0700 |
---|---|---|
committer | Jeremy Evans <[email protected]> | 2021-07-27 11:00:45 -0700 |
commit | 35e467080ca35a9a129e95f802f102c3bc0a81b3 (patch) | |
tree | 162489bbf3dd40c61af61f0fe2f452205957126b /numeric.c | |
parent | 338b604b3216b633d0fc897a915168104f20a514 (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.c | 10 |
1 files changed, 7 insertions, 3 deletions
@@ -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)); |