commit 441b8e6fe7b995e6cd29d33c7ea7f37b87d60d3b Author: Marc-Andre Lafortune Date: Fri Feb 17 19:10:21 2012 -0500 * numeric.c (flodivmod): Fix for cornercases [Bug #xxxx] * insns.def (opt_mod): Bring up to date with flodivmod * test/ruby/test_float.rb: tests for above * test/ruby/envutil.rb: create helper assert_is_minus_zero diff --git a/insns.def b/insns.def index 59a98c0..dbde0bc 100644 --- a/insns.def +++ b/insns.def @@ -1620,19 +1620,21 @@ opt_mod BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { double x = RFLOAT_VALUE(recv); double y = RFLOAT_VALUE(obj); - double div, mod; - - { + double mod; +#ifdef HAVE_FMOD + mod = fmod(x, y); +#else + if((x == -0.0) || (isinf(y) && !isinf(x))) + mod = x; + else { double z; - modf(x / y, &z); + modf(x/y, &z); mod = x - z * y; } - - div = (x - mod) / y; +#endif if (y * mod < 0) { mod += y; - div -= 1.0; } val = DBL2NUM(mod); } diff --git a/numeric.c b/numeric.c index 3b09fea..6a4518d 100644 --- a/numeric.c +++ b/numeric.c @@ -811,19 +811,27 @@ flo_quo(VALUE x, VALUE y) static void flodivmod(double x, double y, double *divp, double *modp) { + /****** + Modifications to this implementation should be mirrored in insns.def + *******/ + double div, mod; if (y == 0.0) rb_num_zerodiv(); + #ifdef HAVE_FMOD mod = fmod(x, y); #else - { + if((x == -0.0) || (isinf(y) && !isinf(x))) + mod = x; + else { double z; modf(x/y, &z); mod = x - z * y; } #endif + if (isinf(x) && !isinf(y) && !isnan(y)) div = x; else diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb index 69b037b..0f9c453 100644 --- a/test/ruby/envutil.rb +++ b/test/ruby/envutil.rb @@ -206,6 +206,10 @@ module Test assert_equal([true, ""], [status.success?, err], message) assert_operator(after.fdiv(before), :<, limit, message) end + + def assert_is_minus_zero(f) + assert(1.0/f == -Float::INFINITY, "#{f} is not -0.0") + end end end end diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index 1935cfd..ba94cb0 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -195,6 +195,13 @@ class TestFloat < Test::Unit::TestCase assert_raise(TypeError) { 2.0.send(:%, nil) } end + def test_modulo3 + assert_equal(4.2, 4.2.send(:%, Float::INFINITY)) + assert_equal(4.2, 4.2 % Float::INFINITY) + assert_is_minus_zero(-0.0 % 4.2) + assert_is_minus_zero(-0.0.send :%, 4.2) + end + def test_divmod2 assert_equal([1.0, 0.0], 2.0.divmod(2)) assert_equal([1.0, 0.0], 2.0.divmod((2**32).coerce(2).first))