Skip to content

Commit 6893bfc

Browse files
committed
Fix divmod and modulo by infinity to match Float#divmod and Float#modulo
1 parent 07696bc commit 6893bfc

File tree

2 files changed

+29
-11
lines changed

2 files changed

+29
-11
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,17 +1733,25 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
17331733
*mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
17341734
goto Done;
17351735
}
1736-
if (VpIsInf(b.real)) {
1737-
VALUE zero = BigDecimal_positive_zero();
1738-
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1739-
*mod = bdvalue_nullable(a);
1740-
goto Done;
1741-
}
17421736
if (VpIsZero(a.real)) {
17431737
VALUE zero = BigDecimal_positive_zero();
17441738
*div = *mod = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
17451739
goto Done;
17461740
}
1741+
if (VpIsInf(b.real)) {
1742+
if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
1743+
BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
1744+
VpSetOne(minus_one.real);
1745+
VpSetSign(minus_one.real, -1);
1746+
*div = bdvalue_nullable(minus_one);
1747+
*mod = bdvalue_nullable(b);
1748+
} else {
1749+
VALUE zero = BigDecimal_positive_zero();
1750+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1751+
*mod = bdvalue_nullable(a);
1752+
}
1753+
goto Done;
1754+
}
17471755

17481756
a_exponent = VpExponent10(a.real);
17491757
b_exponent = VpExponent10(b.real);

test/bigdecimal/test_bigdecimal.rb

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,14 +2697,24 @@ def test_llong_min_gh_200
26972697
assert_equal(BigDecimal(minus_ullong_max.to_s), BigDecimal(minus_ullong_max), "[GH-200]")
26982698
end
26992699

2700-
def test_reminder_infinity_gh_187
2701-
# https://github.com/ruby/bigdecimal/issues/187
2700+
def test_divmod_modulo_remainder_infinity
2701+
pend '-4.2.divmod(Float::INFINITY) is not [-1, Infinity]' if RUBY_ENGINE == 'truffleruby'
27022702
BigDecimal.save_exception_mode do
27032703
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false)
27042704
BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
2705-
bd = BigDecimal("4.2")
2706-
assert_equal(bd.remainder(BigDecimal("+Infinity")), bd)
2707-
assert_equal(bd.remainder(BigDecimal("-Infinity")), bd)
2705+
pinf = BigDecimal("+Infinity")
2706+
minf = BigDecimal("-Infinity")
2707+
assert_nan(pinf.modulo(pinf))
2708+
assert_nan(pinf.remainder(pinf))
2709+
[BigDecimal("-4.2"), BigDecimal(0), BigDecimal("4.2")].each do |x|
2710+
assert_equal(x.to_f.divmod(pinf.to_f), x.divmod(pinf))
2711+
assert_equal(x.to_f.divmod(minf.to_f), x.divmod(minf))
2712+
assert_equal(x.to_f.modulo(pinf.to_f), x.modulo(pinf))
2713+
assert_equal(x.to_f.modulo(minf.to_f), x.modulo(minf))
2714+
# Float#remainder(plus_or_minus_infinity) returns itself Ruby >= 3.1
2715+
assert_equal(x, x.remainder(pinf))
2716+
assert_equal(x, x.remainder(minf))
2717+
end
27082718
end
27092719
end
27102720

0 commit comments

Comments
 (0)