diff --git a/math.c b/math.c index d099e254d9..f0237d4fa9 100644 --- a/math.c +++ b/math.c @@ -40,6 +40,10 @@ VALUE rb_eMathDomainError; #define domain_error(msg) \ rb_raise(rb_eMathDomainError, "Numerical argument is out of domain - " msg) +#define domain_check_min(val, min, msg) \ + ((val) < (min) ? domain_error(msg) : (void)0) +#define domain_check_range(val, min, max, msg) \ + ((val) < (min) || (max) < (val) ? domain_error(msg) : (void)0) /* * call-seq: @@ -184,8 +188,7 @@ math_acos(VALUE unused_obj, VALUE x) double d; d = Get_Double(x); - /* check for domain error */ - if (d < -1.0 || 1.0 < d) domain_error("acos"); + domain_check_range(d, -1.0, 1.0, "acos"); return DBL2NUM(acos(d)); } @@ -208,8 +211,7 @@ math_asin(VALUE unused_obj, VALUE x) double d; d = Get_Double(x); - /* check for domain error */ - if (d < -1.0 || 1.0 < d) domain_error("asin"); + domain_check_range(d, -1.0, 1.0, "asin"); return DBL2NUM(asin(d)); } @@ -343,8 +345,7 @@ math_acosh(VALUE unused_obj, VALUE x) double d; d = Get_Double(x); - /* check for domain error */ - if (d < 1.0) domain_error("acosh"); + domain_check_min(d, 1.0, "acosh"); return DBL2NUM(acosh(d)); } @@ -388,8 +389,7 @@ math_atanh(VALUE unused_obj, VALUE x) double d; d = Get_Double(x); - /* check for domain error */ - if (d < -1.0 || +1.0 < d) domain_error("atanh"); + domain_check_range(d, -1.0, +1.0, "atanh"); /* check for pole error */ if (d == -1.0) return DBL2NUM(-HUGE_VAL); if (d == +1.0) return DBL2NUM(+HUGE_VAL); @@ -501,8 +501,7 @@ math_log1(VALUE x) size_t numbits; double d = get_double_rshift(x, &numbits); - /* check for domain error */ - if (d < 0.0) domain_error("log"); + domain_check_min(d, 0.0, "log"); /* check for pole error */ if (d == 0.0) return -HUGE_VAL; @@ -544,8 +543,7 @@ math_log2(VALUE unused_obj, VALUE x) size_t numbits; double d = get_double_rshift(x, &numbits); - /* check for domain error */ - if (d < 0.0) domain_error("log2"); + domain_check_min(d, 0.0, "log2"); /* check for pole error */ if (d == 0.0) return DBL2NUM(-HUGE_VAL); @@ -574,8 +572,7 @@ math_log10(VALUE unused_obj, VALUE x) size_t numbits; double d = get_double_rshift(x, &numbits); - /* check for domain error */ - if (d < 0.0) domain_error("log10"); + domain_check_min(d, 0.0, "log10"); /* check for pole error */ if (d == 0.0) return DBL2NUM(-HUGE_VAL); @@ -656,8 +653,7 @@ rb_math_sqrt(VALUE x) return rb_complex_new(DBL2NUM(re), DBL2NUM(im)); } d = Get_Double(x); - /* check for domain error */ - if (d < 0.0) domain_error("sqrt"); + domain_check_min(d, 0.0, "sqrt"); if (d == 0.0) return DBL2NUM(0.0); return DBL2NUM(sqrt(d)); } @@ -886,7 +882,7 @@ math_gamma(VALUE unused_obj, VALUE x) return signbit(d) ? DBL2NUM(-HUGE_VAL) : DBL2NUM(HUGE_VAL); } if (d == floor(d)) { - if (d < 0.0) domain_error("gamma"); + domain_check_min(d, 0.0, "gamma"); if (1.0 <= d && d <= (double)NFACT_TABLE) { return DBL2NUM(fact_table[(int)d - 1]); } diff --git a/test/ruby/test_math.rb b/test/ruby/test_math.rb index abfb980e64..73f44c6ae3 100644 --- a/test/ruby/test_math.rb +++ b/test/ruby/test_math.rb @@ -158,9 +158,13 @@ class TestMath < Test::Unit::TestCase assert_nothing_raised { assert_infinity(-Math.log(+0.0)) } assert_nothing_raised { assert_infinity(-Math.log(-0.0)) } assert_raise_with_message(Math::DomainError, /\blog\b/) { Math.log(-1.0) } + assert_raise_with_message(Math::DomainError, /\blog\b/) { Math.log(-Float::EPSILON) } assert_raise(TypeError) { Math.log(1,nil) } - assert_raise(Math::DomainError, '[ruby-core:62309] [ruby-Bug #9797]') { Math.log(1.0, -1.0) } + assert_raise_with_message(Math::DomainError, /\blog\b/, '[ruby-core:62309] [ruby-Bug #9797]') { Math.log(1.0, -1.0) } + assert_raise_with_message(Math::DomainError, /\blog\b/) { Math.log(1.0, -Float::EPSILON) } assert_nothing_raised { assert_nan(Math.log(0.0, 0.0)) } + assert_nothing_raised { assert_nan(Math.log(Float::NAN)) } + assert_nothing_raised { assert_nan(Math.log(1.0, Float::NAN)) } end def test_log2 @@ -173,6 +177,8 @@ class TestMath < Test::Unit::TestCase assert_nothing_raised { assert_infinity(-Math.log2(+0.0)) } assert_nothing_raised { assert_infinity(-Math.log2(-0.0)) } assert_raise_with_message(Math::DomainError, /\blog2\b/) { Math.log2(-1.0) } + assert_raise_with_message(Math::DomainError, /\blog2\b/) { Math.log2(-Float::EPSILON) } + assert_nothing_raised { assert_nan(Math.log2(Float::NAN)) } end def test_log10 @@ -185,6 +191,8 @@ class TestMath < Test::Unit::TestCase assert_nothing_raised { assert_infinity(-Math.log10(+0.0)) } assert_nothing_raised { assert_infinity(-Math.log10(-0.0)) } assert_raise_with_message(Math::DomainError, /\blog10\b/) { Math.log10(-1.0) } + assert_raise_with_message(Math::DomainError, /\blog10\b/) { Math.log10(-Float::EPSILON) } + assert_nothing_raised { assert_nan(Math.log10(Float::NAN)) } end def test_sqrt @@ -194,6 +202,8 @@ class TestMath < Test::Unit::TestCase assert_nothing_raised { assert_infinity(Math.sqrt(1.0/0)) } assert_equal("0.0", Math.sqrt(-0.0).to_s) # insure it is +0.0, not -0.0 assert_raise_with_message(Math::DomainError, /\bsqrt\b/) { Math.sqrt(-1.0) } + assert_raise_with_message(Math::DomainError, /\bsqrt\b/) { Math.sqrt(-Float::EPSILON) } + assert_nothing_raised { assert_nan(Math.sqrt(Float::NAN)) } end def test_cbrt @@ -204,6 +214,8 @@ class TestMath < Test::Unit::TestCase check(0.0, Math.cbrt(0.0)) assert_nothing_raised { assert_infinity(Math.cbrt(1.0/0)) } assert_operator(Math.cbrt(1.0 - Float::EPSILON), :<=, 1.0) + assert_nothing_raised { assert_nan(Math.sqrt(Float::NAN)) } + assert_nothing_raised { assert_nan(Math.cbrt(Float::NAN)) } end def test_frexp @@ -212,6 +224,7 @@ class TestMath < Test::Unit::TestCase assert_float_and_int([0.5, 1], Math.frexp(1.0)) assert_float_and_int([0.5, 2], Math.frexp(2.0)) assert_float_and_int([0.75, 2], Math.frexp(3.0)) + assert_nan(Math.frexp(Float::NAN)[0]) end def test_ldexp @@ -229,11 +242,13 @@ class TestMath < Test::Unit::TestCase def test_erf check(0, Math.erf(0)) check(1, Math.erf(1.0 / 0.0)) + assert_nan(Math.erf(Float::NAN)) end def test_erfc check(1, Math.erfc(0)) check(0, Math.erfc(1.0 / 0.0)) + assert_nan(Math.erfc(Float::NAN)) end def test_gamma @@ -259,10 +274,12 @@ class TestMath < Test::Unit::TestCase end assert_raise_with_message(Math::DomainError, /\bgamma\b/) { Math.gamma(-Float::INFINITY) } + assert_raise_with_message(Math::DomainError, /\bgamma\b/) { Math.gamma(-1.0) } x = Math.gamma(-0.0) mesg = "Math.gamma(-0.0) should be -INF" assert_infinity(x, mesg) assert_predicate(x, :negative?, mesg) + assert_nan(Math.gamma(Float::NAN)) end def test_lgamma @@ -284,6 +301,8 @@ class TestMath < Test::Unit::TestCase assert_infinity(x, mesg) assert_predicate(x, :positive?, mesg) assert_equal(-1, sign, mesg) + x, sign = Math.lgamma(Float::NAN) + assert_nan(x) end def test_fixnum_to_f