Skip to content

Commit 8ca3249

Browse files
authored
Fix divmod and modulo by infinity to match Float#divmod and Float#modulo (#429)
1 parent 34e60a7 commit 8ca3249

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,17 +1733,26 @@ 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+
RB_GC_GUARD(minus_one.bigdecimal);
1747+
*div = bdvalue_nullable(minus_one);
1748+
*mod = bdvalue_nullable(b);
1749+
} else {
1750+
VALUE zero = BigDecimal_positive_zero();
1751+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1752+
*mod = bdvalue_nullable(a);
1753+
}
1754+
goto Done;
1755+
}
17471756

17481757
a_exponent = VpExponent10(a.real);
17491758
b_exponent = VpExponent10(b.real);

test/bigdecimal/test_bigdecimal.rb

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

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

0 commit comments

Comments
 (0)