diff options
author | Kenta Murata <[email protected]> | 2021-01-22 13:49:46 +0900 |
---|---|---|
committer | Kenta Murata <[email protected]> | 2021-12-24 02:28:55 +0900 |
commit | 7b2cfce543b876744544c8b43abdee3c72cab910 (patch) | |
tree | 7d41e1f733856b4206a9987d6c8a7d462fad24f2 | |
parent | e1265c819870c6a4d6763529e9fbd2d70c722fe0 (diff) |
[ruby/bigdecimal] Let BigDecimal_DoDivmod use the same precision calculation as BigDecimal_divide
https://github.com/ruby/bigdecimal/commit/11cb2c8840
-rw-r--r-- | ext/bigdecimal/bigdecimal.c | 33 | ||||
-rw-r--r-- | 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 71499a7a19..0558a17fd9 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) 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 66b58aa124..26d346b364 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -1043,6 +1043,13 @@ class TestBigDecimal < Test::Unit::TestCase 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 |