summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numeric.c10
-rw-r--r--test/ruby/test_numeric.rb9
2 files changed, 16 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));
diff --git a/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb
index 066afc83a2..b5486d387c 100644
--- a/test/ruby/test_numeric.rb
+++ b/test/ruby/test_numeric.rb
@@ -229,6 +229,15 @@ class TestNumeric < Test::Unit::TestCase
assert_equal(-1, a.truncate)
end
+ def test_floor_ceil_ndigits
+ bug17183 = "[ruby-core:100090]"
+ f = 291.4
+ 31.times do |i|
+ assert_equal(291.4, f.floor(i+1), bug17183)
+ assert_equal(291.4, f.ceil(i+1), bug17183)
+ end
+ end
+
def assert_step(expected, (from, *args), inf: false)
kw = args.last.is_a?(Hash) ? args.pop : {}
enum = from.step(*args, **kw)