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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy