Skip to content

Commit 74cd039

Browse files
committed
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 #13754] [Fix GH-94]
1 parent 3b55ad1 commit 74cd039

File tree

2 files changed

+19
-9
lines changed

2 files changed

+19
-9
lines changed

ext/bigdecimal/bigdecimal.c

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

13771377
*div = b;
1378-
mx = a->Prec + vabs(a->exponent);
1379-
if (mx < b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
1380-
mx++; /* NOTE: An additional digit is needed for the compatibility to
1381-
the version 1.2.1 and the former. */
1382-
mx = (mx + 1) * VpBaseFig();
1383-
GUARD_OBJ((*c), VpCreateRbObject(mx, "#0", true));
1384-
GUARD_OBJ((*res), VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0", true));
1378+
mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
1379+
mx *= BASE_FIG;
1380+
if (2*DBLE_FIG > mx)
1381+
mx = 2*DBLE_FIG;
1382+
GUARD_OBJ((*c), VpCreateRbObject(mx + 2*BASE_FIG, "#0", true));
1383+
GUARD_OBJ((*res), VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
13851384
VpDivd(*c, *res, a, b);
13861385
return Qnil;
13871386
}

test/bigdecimal/test_bigdecimal.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -936,9 +936,11 @@ def test_div
936936
assert_equal(2, BigDecimal("2") / 1)
937937
assert_equal(-2, BigDecimal("2") / -1)
938938

939-
assert_equal(BigDecimal('1486.868686869'), BigDecimal('1472.0') / BigDecimal('0.99'), '[ruby-core:59365] [#9316]')
939+
assert_not_equal(BigDecimal('1487.0'), BigDecimal('1472.0') / BigDecimal('0.99'), '[ruby-core:59365] [#9316]')
940940

941-
assert_equal(4.124045235, BigDecimal('0.9932') / (700 * BigDecimal('0.344045') / BigDecimal('1000.0')), '[#9305]')
941+
assert_in_delta(4.124045235,
942+
(BigDecimal('0.9932') / (700 * BigDecimal('0.344045') / BigDecimal('1000.0'))).round(9, half: :up),
943+
10**Float::MIN_10_EXP, '[#9305]')
942944

943945
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false)
944946
assert_positive_zero(BigDecimal("1.0") / BigDecimal("Infinity"))
@@ -952,6 +954,15 @@ def test_div
952954
assert_raise_with_message(FloatDomainError, "Computation results to '-Infinity'") { BigDecimal("-1") / 0 }
953955
end
954956

957+
def test_dev_precision
958+
bug13754 = '[ruby-core:82107] [Bug #13754]'
959+
a = BigDecimal('101')
960+
b = BigDecimal('0.9163472602589686')
961+
c = a/b
962+
assert(c.precision > b.precision,
963+
"(101/0.9163472602589686).precision >= (0.9163472602589686).precision #{bug13754}")
964+
end
965+
955966
def test_div_with_float
956967
assert_kind_of(BigDecimal, BigDecimal("3") / 1.5)
957968
assert_equal(BigDecimal("0.5"), BigDecimal(1) / 2.0)

0 commit comments

Comments
 (0)