Skip to content

Commit

Permalink
[ruby/bigdecimal] Let BigDecimal_DoDivmod use the same precision calc…
Browse files Browse the repository at this point in the history
…ulation as BigDecimal_divide

ruby/bigdecimal@11cb2c8840
  • Loading branch information
mrkn committed Dec 23, 2021
1 parent e1265c8 commit 7b2cfce
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 13 deletions.
33 changes: 20 additions & 13 deletions ext/bigdecimal/bigdecimal.c
Expand Up @@ -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;

Expand Down
7 changes: 7 additions & 0 deletions test/bigdecimal/test_bigdecimal.rb
Expand Up @@ -1043,6 +1043,13 @@ def test_divmod
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
Expand Down

0 comments on commit 7b2cfce

Please sign in to comment.