[前][次][番号順一覧][スレッド一覧]

ruby-changes:66918

From: Jeremy <ko1@a...>
Date: Wed, 28 Jul 2021 03:00:57 +0900 (JST)
Subject: [ruby-changes:66918] 35e467080c (master): Make Float#floor with ndigits argument handle error

https://git.ruby-lang.org/ruby.git/commit/?id=35e467080c

From 35e467080ca35a9a129e95f802f102c3bc0a81b3 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Mon, 26 Jul 2021 10:45:56 -0700
Subject: 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]
---
 numeric.c                 | 10 +++++++---
 test/ruby/test_numeric.rb |  9 +++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/numeric.c b/numeric.c
index 345067c..5564a6e 100644
--- a/numeric.c
+++ b/numeric.c
@@ -1829,20 +1829,24 @@ flo_prev_float(VALUE vx) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1829
 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 066afc8..b5486d3 100644
--- a/test/ruby/test_numeric.rb
+++ b/test/ruby/test_numeric.rb
@@ -229,6 +229,15 @@ class TestNumeric < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_numeric.rb#L229
     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)
-- 
cgit v1.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]