diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 1eca3ef2..2c00e472 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -1733,17 +1733,26 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) }; goto Done; } - if (VpIsInf(b.real)) { - VALUE zero = BigDecimal_positive_zero(); - *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) }; - *mod = bdvalue_nullable(a); - goto Done; - } if (VpIsZero(a.real)) { VALUE zero = BigDecimal_positive_zero(); *div = *mod = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) }; goto Done; } + if (VpIsInf(b.real)) { + if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) { + BDVALUE minus_one = NewZeroWrap(1, BASE_FIG); + VpSetOne(minus_one.real); + VpSetSign(minus_one.real, -1); + RB_GC_GUARD(minus_one.bigdecimal); + *div = bdvalue_nullable(minus_one); + *mod = bdvalue_nullable(b); + } else { + VALUE zero = BigDecimal_positive_zero(); + *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) }; + *mod = bdvalue_nullable(a); + } + goto Done; + } a_exponent = VpExponent10(a.real); b_exponent = VpExponent10(b.real); diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index 65de3a45..0465ae91 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -2697,14 +2697,24 @@ def test_llong_min_gh_200 assert_equal(BigDecimal(minus_ullong_max.to_s), BigDecimal(minus_ullong_max), "[GH-200]") end - def test_reminder_infinity_gh_187 - # https://github.com/ruby/bigdecimal/issues/187 + def test_divmod_modulo_remainder_infinity + pend '-4.2.divmod(Float::INFINITY) is not [-1, Infinity]' if RUBY_ENGINE == 'truffleruby' BigDecimal.save_exception_mode do BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false) BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) - bd = BigDecimal("4.2") - assert_equal(bd.remainder(BigDecimal("+Infinity")), bd) - assert_equal(bd.remainder(BigDecimal("-Infinity")), bd) + pinf = BigDecimal("+Infinity") + minf = BigDecimal("-Infinity") + assert_nan(pinf.modulo(pinf)) + assert_nan(pinf.remainder(pinf)) + [BigDecimal("-4.2"), BigDecimal(0), BigDecimal("4.2")].each do |x| + assert_equal(x.to_f.divmod(pinf.to_f), x.divmod(pinf)) + assert_equal(x.to_f.divmod(minf.to_f), x.divmod(minf)) + assert_equal(x.to_f.modulo(pinf.to_f), x.modulo(pinf)) + assert_equal(x.to_f.modulo(minf.to_f), x.modulo(minf)) + # Float#remainder(plus_or_minus_infinity) returns itself in Ruby >= 3.1 + assert_equal(x, x.remainder(pinf)) + assert_equal(x, x.remainder(minf)) + end end end