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

ruby-changes:70484

From: Kenta <ko1@a...>
Date: Fri, 24 Dec 2021 02:30:26 +0900 (JST)
Subject: [ruby-changes:70484] 7b2cfce543 (master): [ruby/bigdecimal] Let BigDecimal_DoDivmod use the same precision calculation as BigDecimal_divide

https://git.ruby-lang.org/ruby.git/commit/?id=7b2cfce543

From 7b2cfce543b876744544c8b43abdee3c72cab910 Mon Sep 17 00:00:00 2001
From: Kenta Murata <mrkn@m...>
Date: Fri, 22 Jan 2021 13:49:46 +0900
Subject: [ruby/bigdecimal] Let BigDecimal_DoDivmod use the same precision
 calculation as BigDecimal_divide

https://github.com/ruby/bigdecimal/commit/11cb2c8840
---
 ext/bigdecimal/bigdecimal.c        | 33 ++++++++++++++++++++-------------
 test/bigdecimal/test_bigdecimal.rb |  7 +++++++
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index 71499a7a19f..0558a17fd9c 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -1613,26 +1613,33 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L1613
         return Qtrue;
     }
 
-    mx = a->Prec + vabs(a->exponent);
-    if (mx<b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
-    mx = (mx + 1) * VpBaseFig();
-    GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
-    GUARD_OBJ(res, VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0", true));
+    mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
+    mx *= BASE_FIG;
+    if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
+        mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
+
+    GUARD_OBJ(c, VpCreateRbObject(mx + 2*BASE_FIG, "0", true));
+    GUARD_OBJ(res, VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
     VpDivd(c, res, a, b);
-    mx = c->Prec * (VpBaseFig() + 1);
+
+    mx = c->Prec * BASE_FIG;
     GUARD_OBJ(d, VpCreateRbObject(mx, "0", true));
     VpActiveRound(d, c, VP_ROUND_DOWN, 0);
+
     VpMult(res, d, b);
     VpAddSub(c, a, res, -1);
+
     if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
-	VpAddSub(res, d, VpOne(), -1);
+        /* remainder adjustment for negative case */
+        VpAddSub(res, d, VpOne(), -1);
         GUARD_OBJ(d, VpCreateRbObject(GetAddSubPrec(c, b)*(VpBaseFig() + 1), "0", true));
-	VpAddSub(d, c, b, 1);
-	*div = res;
-	*mod = d;
-    } else {
-	*div = d;
-	*mod = c;
+        VpAddSub(d, c, b, 1);
+        *div = res;
+        *mod = d;
+    }
+    else {
+        *div = d;
+        *mod = c;
     }
     return Qtrue;
 
diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb
index 66b58aa1248..26d346b3646 100644
--- a/test/bigdecimal/test_bigdecimal.rb
+++ b/test/bigdecimal/test_bigdecimal.rb
@@ -1043,6 +1043,13 @@ class TestBigDecimal < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/bigdecimal/test_bigdecimal.rb#L1043
     assert_raise(ZeroDivisionError){BigDecimal("0").divmod(0)}
   end
 
+  def test_divmod_precision
+    a = BigDecimal('2e55')
+    b = BigDecimal('1.23456789e10')
+    q, r = a.divmod(b)
+    assert_equal((a/b), q)
+  end
+
   def test_divmod_error
     assert_raise(TypeError) { BigDecimal(20).divmod('2') }
   end
-- 
cgit v1.2.1


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

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