Add domain check macros

This commit is contained in:
Nobuyoshi Nakada 2021-07-04 19:22:11 +09:00
parent 2488589b2f
commit 0a32cefabd
No known key found for this signature in database
GPG Key ID: 7CD2805BFA3770C6
2 changed files with 33 additions and 18 deletions

30
math.c
View File

@ -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]);
}

View File

@ -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