Skip to content

Commit 41ff5dd

Browse files
committed
[ruby/bigdecimal] Use larger precision in divide for irrational or recurring results
Just in case for irrational or recurring results, the precision of the quotient is set to at least more than 2*Float::DIG plus alpha. [Bug ruby#13754] [Fix rubyGH-94] ruby/bigdecimal@99442c75d3
1 parent 0794b2c commit 41ff5dd

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,13 +1508,12 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
15081508
SAVE(b);
15091509

15101510
*div = b;
1511-
mx = a->Prec + vabs(a->exponent);
1512-
if (mx < b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
1513-
mx++; /* NOTE: An additional digit is needed for the compatibility to
1514-
the version 1.2.1 and the former. */
1515-
mx = (mx + 1) * VpBaseFig();
1516-
GUARD_OBJ((*c), VpCreateRbObject(mx, "#0", true));
1517-
GUARD_OBJ((*res), VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0", true));
1511+
mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
1512+
mx *= BASE_FIG;
1513+
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1514+
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1515+
GUARD_OBJ((*c), VpCreateRbObject(mx + 2*BASE_FIG, "#0", true));
1516+
GUARD_OBJ((*res), VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
15181517
VpDivd(*c, *res, a, b);
15191518
return Qnil;
15201519
}

test/bigdecimal/test_bigdecimal.rb

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -953,9 +953,13 @@ def test_div
953953
assert_equal(2, BigDecimal("2") / 1)
954954
assert_equal(-2, BigDecimal("2") / -1)
955955

956-
assert_equal(BigDecimal('1486.868686869'), BigDecimal('1472.0') / BigDecimal('0.99'), '[ruby-core:59365] [#9316]')
956+
assert_equal(BigDecimal('1486.868686869'),
957+
(BigDecimal('1472.0') / BigDecimal('0.99')).round(9),
958+
'[ruby-core:59365] [#9316]')
957959

958-
assert_equal(4.124045235, BigDecimal('0.9932') / (700 * BigDecimal('0.344045') / BigDecimal('1000.0')), '[#9305]')
960+
assert_in_delta(4.124045235,
961+
(BigDecimal('0.9932') / (700 * BigDecimal('0.344045') / BigDecimal('1000.0'))).round(9, half: :up),
962+
10**Float::MIN_10_EXP, '[#9305]')
959963

960964
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false)
961965
assert_positive_zero(BigDecimal("1.0") / BigDecimal("Infinity"))
@@ -969,6 +973,15 @@ def test_div
969973
assert_raise_with_message(FloatDomainError, "Computation results in '-Infinity'") { BigDecimal("-1") / 0 }
970974
end
971975

976+
def test_dev_precision
977+
bug13754 = '[ruby-core:82107] [Bug #13754]'
978+
a = BigDecimal('101')
979+
b = BigDecimal('0.9163472602589686')
980+
c = a/b
981+
assert(c.precision > b.precision,
982+
"(101/0.9163472602589686).precision >= (0.9163472602589686).precision #{bug13754}")
983+
end
984+
972985
def test_div_with_float
973986
assert_kind_of(BigDecimal, BigDecimal("3") / 1.5)
974987
assert_equal(BigDecimal("0.5"), BigDecimal(1) / 2.0)

0 commit comments

Comments
 (0)