Skip to content

Commit 11cb2c8

Browse files
committed
Let BigDecimal_DoDivmod use the same precision calculation as BigDecimal_divide
1 parent 99442c7 commit 11cb2c8

File tree

2 files changed

+27
-13
lines changed

2 files changed

+27
-13
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,26 +1613,33 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
16131613
return Qtrue;
16141614
}
16151615

1616-
mx = a->Prec + vabs(a->exponent);
1617-
if (mx<b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
1618-
mx = (mx + 1) * VpBaseFig();
1619-
GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
1620-
GUARD_OBJ(res, VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0", true));
1616+
mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
1617+
mx *= BASE_FIG;
1618+
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1619+
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1620+
1621+
GUARD_OBJ(c, VpCreateRbObject(mx + 2*BASE_FIG, "0", true));
1622+
GUARD_OBJ(res, VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
16211623
VpDivd(c, res, a, b);
1622-
mx = c->Prec * (VpBaseFig() + 1);
1624+
1625+
mx = c->Prec * BASE_FIG;
16231626
GUARD_OBJ(d, VpCreateRbObject(mx, "0", true));
16241627
VpActiveRound(d, c, VP_ROUND_DOWN, 0);
1628+
16251629
VpMult(res, d, b);
16261630
VpAddSub(c, a, res, -1);
1631+
16271632
if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1628-
VpAddSub(res, d, VpOne(), -1);
1633+
/* remainder adjustment for negative case */
1634+
VpAddSub(res, d, VpOne(), -1);
16291635
GUARD_OBJ(d, VpCreateRbObject(GetAddSubPrec(c, b)*(VpBaseFig() + 1), "0", true));
1630-
VpAddSub(d, c, b, 1);
1631-
*div = res;
1632-
*mod = d;
1633-
} else {
1634-
*div = d;
1635-
*mod = c;
1636+
VpAddSub(d, c, b, 1);
1637+
*div = res;
1638+
*mod = d;
1639+
}
1640+
else {
1641+
*div = d;
1642+
*mod = c;
16361643
}
16371644
return Qtrue;
16381645

test/bigdecimal/test_bigdecimal.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,13 @@ def test_divmod
10431043
assert_raise(ZeroDivisionError){BigDecimal("0").divmod(0)}
10441044
end
10451045

1046+
def test_divmod_precision
1047+
a = BigDecimal('2e55')
1048+
b = BigDecimal('1.23456789e10')
1049+
q, r = a.divmod(b)
1050+
assert_equal((a/b), q)
1051+
end
1052+
10461053
def test_divmod_error
10471054
assert_raise(TypeError) { BigDecimal(20).divmod('2') }
10481055
end

0 commit comments

Comments
 (0)