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/