1. Build tests with -fno-builtin so we actually test libm and not the compiler's constant-folding. (We should _also_ test what the compiler does but that's another issue.) 2. Fix up last few digits of a lot of known-answer tests. Confirmed with GNU mpfr to 200 bits of precision and cross-checked with whatever libm Ubuntu ships with. 3. Test relative error, not absolute error. 4. Set bounds in terms of *_EPSILON, which is twice the largest relative error of a correctly rounded operation, or 0.5ulp. Most of the operations we're testing are not correctly rounded but they ought to be no more than 1ulp away. For the few cases where that's not a priori clear (like comparing cbrt and pow(x, 1/3)), use twice *_EPSILON to allow some leeway. 5. Write the success condition positively as fabs((a - e)/a) <= eps, and then test whether it is false, so that if the relative error is large _or_ if the outcome is NaN, we will report a failure. (In contrast, fabs((a - e)/a) > eps is false if the result is NaN, so we would not report a failure in that case.) 6. Fix the trigonometric test cases near bad spots. sin(pi - d) for nonzero d is not zero; it is d + O(d^3). pi is not a floating-point number, so these results should be approximately the nonzero error of our approximation to pi. Likewise with cos(pi/2 - d) and tan(pi + d). (Yes, I know the sin _function_ is ill-conditioned near pi so you shouldn't pass approximate inputs near there, but that's separate from whether a sin _implementation_ gives an answer that is wrong by quintillions of ulps.) 7. Use %.8g, %.17g, %.35g to print float, double, long double in failures. This should be enough to identify the problematic outputs and/or reproduce the computation, even if long double is binary128 with 115 bits of precision. diff --git a/tests/lib/libm/Makefile b/tests/lib/libm/Makefile index 7ff3df3c171d..bb431d0cc81a 100644 --- a/tests/lib/libm/Makefile +++ b/tests/lib/libm/Makefile @@ -7,6 +7,7 @@ TESTSDIR= ${TESTSBASE}/lib/libm .if ${MACHINE} == "alpha" COPTS+= -mfloat-ieee -mieee-with-inexact -mfp-trap-mode=sui -mtrap-precision=i .endif +COPTS+= -fno-builtin CPPFLAGS.t_fenv.c+= -D__TEST_FENV CPPFLAGS.t_fe_round.c+= -D__TEST_FENV diff --git a/tests/lib/libm/t_acos.c b/tests/lib/libm/t_acos.c index f051fb64df42..ba6930643b16 100644 --- a/tests/lib/libm/t_acos.c +++ b/tests/lib/libm/t_acos.c @@ -72,7 +72,7 @@ ATF_LIBM_TEST(acos_inrange, "Test acos/acosf(x) for some valid values") { 0, M_PI / 2, }, { 0.1, 1.470628905633337, }, { 0.5, 1.047197551196598, }, - { 0.99, 0.141539473324427, }, + { 0.99, 0.1415394733244273, }, }; unsigned int i; diff --git a/tests/lib/libm/t_asin.c b/tests/lib/libm/t_asin.c index 06de85216429..a26698b1031e 100644 --- a/tests/lib/libm/t_asin.c +++ b/tests/lib/libm/t_asin.c @@ -30,6 +30,7 @@ */ #include +#include #include static const struct { @@ -117,13 +118,14 @@ ATF_TC_HEAD(asin_inrange, tc) ATF_TC_BODY(asin_inrange, tc) { - const double eps = 1.0e-15; - double y; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(values); i++) { - y = asin(values[i].x); - if (fabs(y - values[i].y) > eps) + double x = values[i].x; + double y = values[i].y; + + if (!(fabs((asin(x) - y)/y) <= eps)) atf_tc_fail_nonfatal("asin(%g) != %g", values[i].x, values[i].y); } @@ -230,16 +232,22 @@ ATF_TC_HEAD(asinf_inrange, tc) ATF_TC_BODY(asinf_inrange, tc) { - const float eps = 1.0e-6; - float x; - float y; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(values); i++) { - x = values[i].x; - y = values[i].y; - if (fabs(asinf(x) - y) > eps) - atf_tc_fail_nonfatal("asinf(%g) != %g", x, y); + float x = values[i].x; + float y = values[i].y; + + if (fabs(x) == 0.5) + atf_tc_expect_fail("asin is busted, gives ~2ulp error"); + if (!(fabsf((asinf(x) - y)/y) <= eps)) { + atf_tc_fail_nonfatal("asinf(%.8g) = %.8g != %.8g," + " error=~%.1fulp", + x, asinf(x), y, fabsf(((asinf(x) - y)/y)/eps)); + } + if (fabs(x) == 0.5) + atf_tc_expect_pass(); } } diff --git a/tests/lib/libm/t_cbrt.c b/tests/lib/libm/t_cbrt.c index a7de9f629815..bf4cbc3cb5cd 100644 --- a/tests/lib/libm/t_cbrt.c +++ b/tests/lib/libm/t_cbrt.c @@ -32,6 +32,7 @@ __RCSID("$NetBSD: t_cbrt.c,v 1.3 2014/03/03 10:39:08 martin Exp $"); #include +#include #include #include @@ -61,18 +62,26 @@ ATF_TC_HEAD(cbrt_pow, tc) ATF_TC_BODY(cbrt_pow, tc) { const double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 }; - const double eps = 1.0e-14; - double y, z; + /* Neither cbrt nor pow is required to be correctly rounded. */ + const double eps = 2*DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(x); i++) { - - y = cbrt(x[i]); - z = pow(x[i], 1.0 / 3.0); - - if (fabs(y - z) > eps) - atf_tc_fail_nonfatal("cbrt(%0.03f) != " - "pow(%0.03f, 1/3)\n", x[i], x[i]); + double x_cbrt = cbrt(x[i]); + double x_pow13 = pow(x[i], 1.0 / 3.0); + bool ok; + + if (x[i] == 0) { + ok = (x_cbrt == x_pow13); + } else { + ok = (fabs((x_cbrt - x_pow13)/x_cbrt) <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("cbrt(%.17g) = %.17g != " + "pow(%.17g, 1/3) = %.17g\n", + x[i], x_cbrt, x[i], x_pow13); + } } } @@ -162,18 +171,27 @@ ATF_TC_HEAD(cbrtf_powf, tc) ATF_TC_BODY(cbrtf_powf, tc) { const float x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 }; - const float eps = 1.0e-5; - float y, z; + /* Neither cbrt nor pow is required to be correctly rounded. */ + const float eps = 2*FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(x); i++) { - - y = cbrtf(x[i]); - z = powf(x[i], 1.0 / 3.0); - - if (fabsf(y - z) > eps) - atf_tc_fail_nonfatal("cbrtf(%0.03f) != " - "powf(%0.03f, 1/3)\n", x[i], x[i]); + float x_cbrt = cbrtf(x[i]); + float x_pow13 = powf(x[i], 1.0 / 3.0); + bool ok; + + if (x[i] == 0) { + ok = (x_cbrt == x_pow13); + } else { + ok = (fabsf((x_cbrt - x_pow13)/x_cbrt) <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("cbrtf(%.9g) = %.9g. != " + "powf(%.9g, 1/3) = %.9g\n", + (double)x[i], (double)x_cbrt, + (double)x[i], (double)x_pow13); + } } } @@ -263,18 +281,27 @@ ATF_TC_HEAD(cbrtl_powl, tc) ATF_TC_BODY(cbrtl_powl, tc) { const long double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 }; - const long double eps = 1.0e-15; - long double y, z; + /* Neither cbrt nor pow is required to be correctly rounded. */ + const long double eps = 2*LDBL_EPSILON; size_t i; + atf_tc_expect_fail("powl not yet implemented with full precision"); for (i = 0; i < __arraycount(x); i++) { - - y = cbrtl(x[i]); - z = powl(x[i], 1.0 / 3.0); - - if (fabsl(y - z) > eps * fabsl(1 + x[i])) - atf_tc_fail_nonfatal("cbrtl(%0.03Lf) != " - "powl(%0.03Lf, 1/3)\n", x[i], x[i]); + long double x_cbrt = cbrtl(x[i]); + long double x_pow13 = powl(x[i], 1.0 / 3.0); + bool ok; + + if (x[i] == 0) { + ok = (x_cbrt == x_pow13); + } else { + ok = (fabsl((x_cbrt - x_pow13)/x_cbrt) <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("cbrtl(%.35Lg) = %.35Lg != " + "powl(%.35Lg, 1/3) = %.35Lg\n", + x[i], x_cbrt, x[i], x_pow13); + } } } diff --git a/tests/lib/libm/t_cos.c b/tests/lib/libm/t_cos.c index d99d60810eeb..8c23352f1029 100644 --- a/tests/lib/libm/t_cos.c +++ b/tests/lib/libm/t_cos.c @@ -29,29 +29,41 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include +#include #include +#if defined(__i386__) || defined(__x86_64__) +const int TRIG_BUSTED = 1; +#else +const int TRIG_BUSTED = 0; +#endif + static const struct { int angle; double x; double y; + float fy; } angles[] = { - { -180, -3.141592653589793, -1.0000000000000000 }, - { -135, -2.356194490192345, -0.7071067811865476 }, - { -90, -1.570796326794897, 0.0000000000000000 }, - { -45, -0.785398163397448, 0.7071067811865476 }, - { 0, 0.000000000000000, 1.0000000000000000 }, - { 30, 0.523598775598299, 0.8660254037844386 }, - { 45, 0.785398163397448, 0.7071067811865476 }, - { 60, 1.047197551196598, 0.5000000000000000 }, - { 90, 1.570796326794897, 0.0000000000000000 }, - { 120, 2.094395102393195, -0.5000000000000000 }, - { 135, 2.356194490192345, -0.7071067811865476 }, - { 150, 2.617993877991494, -0.8660254037844386 }, - { 180, 3.141592653589793, -1.0000000000000000 }, - { 270, 4.712388980384690, 0.0000000000000000 }, - { 360, 6.283185307179586, 1.0000000000000000 } + { -180, -3.141592653589793, -1.0000000000000000, 999 }, + { -135, -2.356194490192345, -0.7071067811865476, 999 }, + { -90, -1.5707963267948966, 6.123233995736766e-17, -4.3711388e-08 }, + { -90, -1.5707963267948968, -1.6081226496766366e-16, -4.3711388e-08 }, + { -45, -0.785398163397448, 0.7071067811865478, 999 }, + { 0, 0.000000000000000, 1.0000000000000000, 999 }, + { 30, 0.523598775598299, 0.8660254037844386, 999 }, + { 45, 0.785398163397448, 0.7071067811865478, 999 }, + { 60, 1.0471975511965976, 0.5000000000000001, 999 }, + { 60, 1.0471975511965979, 0.4999999999999999, 999 }, + { 90, 1.570796326794897, -3.8285686989269494e-16, -4.3711388e-08 }, + { 120, 2.0943951023931953, -0.4999999999999998, 999 }, + { 120, 2.0943951023931957, -0.5000000000000002, 999 }, + { 135, 2.356194490192345, -0.7071067811865476, 999 }, + { 150, 2.617993877991494, -0.8660254037844386, 999 }, + { 180, 3.141592653589793, -1.0000000000000000, 999 }, + { 270, 4.712388980384690, -1.8369701987210297e-16, 1.1924881e-08 }, + { 360, 6.283185307179586, 1.0000000000000000, 999 }, }; /* @@ -65,14 +77,23 @@ ATF_TC_HEAD(cos_angles, tc) ATF_TC_BODY(cos_angles, tc) { - const double eps = 1.0e-15; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(angles); i++) { - - if (fabs(cos(angles[i].x) - angles[i].y) > eps) - atf_tc_fail_nonfatal("cos(%d deg) != %0.01f", - angles[i].angle, angles[i].y); + int deg = angles[i].angle; + double theta = angles[i].x; + double cos_theta = angles[i].y; + + assert(cos_theta != 0); + if (TRIG_BUSTED && fabs(cos_theta) < 2*DBL_EPSILON) + atf_tc_expect_fail("cos near +/-pi/2 is busted"); + if (!(fabs((cos(theta) - cos_theta)/cos_theta) <= eps)) { + atf_tc_fail_nonfatal("cos(%d deg) = %.17g != %.17g", + deg, cos(theta), cos_theta); + } + if (TRIG_BUSTED && fabs(cos_theta) < 2*DBL_EPSILON) + atf_tc_expect_pass(); } } @@ -154,18 +175,22 @@ ATF_TC_HEAD(cosf_angles, tc) ATF_TC_BODY(cosf_angles, tc) { - const float eps = 1.0e-7; - float x, y; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(angles); i++) { - - x = angles[i].x; - y = angles[i].y; - - if (fabsf(cosf(x) - y) > eps) - atf_tc_fail_nonfatal("cosf(%d deg) != %0.01f", - angles[i].angle, angles[i].y); + int deg = angles[i].angle; + float theta = angles[i].x; + float cos_theta = angles[i].fy; + + if (cos_theta == 999) + cos_theta = angles[i].y; + + assert(cos_theta != 0); + if (!(fabsf((cosf(theta) - cos_theta)/cos_theta) <= eps)) { + atf_tc_fail_nonfatal("cosf(%d deg) = %.8g != %.8g", + deg, cos(theta), cos_theta); + } } } diff --git a/tests/lib/libm/t_cosh.c b/tests/lib/libm/t_cosh.c index 3f998de761bb..d60dfd570f92 100644 --- a/tests/lib/libm/t_cosh.c +++ b/tests/lib/libm/t_cosh.c @@ -32,25 +32,25 @@ __RCSID("$NetBSD: t_cosh.c,v 1.6 2014/03/03 10:39:08 martin Exp $"); #include +#include #include #include static const struct { double x; double y; - double e; } values[] = { - { -10, 11013.23292010332, 1e4, }, - { -2, 3.762195691083631, 1, }, - { -1, 1.543080634815244, 1, }, - { -0.05, 1.001250260438369, 1, }, - { -0.001, 1.000000500000042, 1, }, - { 0, 1, 1, }, - { 0.001, 1.000000500000042, 1, }, - { 0.05, 1.001250260438369, 1, }, - { 1, 1.543080634815244, 1, }, - { 2, 3.762195691083631, 1, }, - { 10, 11013.23292010332, 1e4, }, + { -10, 11013.232920103323, }, + { -2, 3.762195691083631, }, + { -1, 1.543080634815244, }, + { -0.05, 1.001250260438369, }, + { -0.001, 1.0000005000000418, }, + { 0, 1, }, + { 0.001, 1.0000005000000418, }, + { 0.05, 1.001250260438369, }, + { 1, 1.543080634815244, }, + { 2, 3.762195691083631, }, + { 10, 11013.232920103323, }, }; /* @@ -64,18 +64,17 @@ ATF_TC_HEAD(cosh_inrange, tc) ATF_TC_BODY(cosh_inrange, tc) { - double eps; - double x; - double y; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(values); i++) { - x = values[i].x; - y = values[i].y; - eps = 1e-15 * values[i].e; + double x = values[i].x; + double cosh_x = values[i].y; - if (fabs(cosh(x) - y) > eps) - atf_tc_fail_nonfatal("cosh(%g) != %g\n", x, y); + if (!(fabs((cosh(x) - cosh_x)/cosh_x) <= eps)) { + atf_tc_fail_nonfatal("cosh(%.17g) = %.17g != %.17g\n", + x, cosh(x), cosh_x); + } } } @@ -162,18 +161,17 @@ ATF_TC_HEAD(coshf_inrange, tc) ATF_TC_BODY(coshf_inrange, tc) { - float eps; - float x; - float y; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(values); i++) { - x = values[i].x; - y = values[i].y; - eps = 1e-6 * values[i].e; + float x = values[i].x; + float cosh_x = values[i].y; - if (fabsf(coshf(x) - y) > eps) - atf_tc_fail_nonfatal("coshf(%g) != %g\n", x, y); + if (!(fabsf((coshf(x) - cosh_x)/cosh_x) <= eps)) { + atf_tc_fail_nonfatal("coshf(%.17g) = %.17g != %.17g\n", + x, coshf(x), cosh_x); + } } } diff --git a/tests/lib/libm/t_exp.c b/tests/lib/libm/t_exp.c index 73ae87b01509..08d58ccf0fa8 100644 --- a/tests/lib/libm/t_exp.c +++ b/tests/lib/libm/t_exp.c @@ -30,6 +30,7 @@ */ #include +#include #include #include "t_libm.h" @@ -37,17 +38,16 @@ static const struct { double x; double y; - double e; } exp_values[] = { - { -10, 0.4539992976248485e-4, 1e-4, }, - { -5, 0.6737946999085467e-2, 1e-2, }, - { -1, 0.3678794411714423, 1e-1, }, - { -0.1, 0.9048374180359595, 1e-1, }, - { 0, 1.0000000000000000, 1, }, - { 0.1, 1.1051709180756477, 1, }, - { 1, 2.7182818284590452, 1, }, - { 5, 148.41315910257660, 1e2, }, - { 10, 22026.465794806718, 1e4, }, + { -10, 0.4539992976248485e-4, }, + { -5, 0.6737946999085467e-2, }, + { -1, 0.3678794411714423, }, + { -0.1, 0.9048374180359595, }, + { 0, 1.0000000000000000, }, + { 0.1, 1.1051709180756477, }, + { 1, 2.7182818284590452, }, + { 5, 148.41315910257660, }, + { 10, 22026.465794806718, }, }; /* @@ -234,18 +234,17 @@ ATF_TC_HEAD(exp_product, tc) ATF_TC_BODY(exp_product, tc) { - double eps; - double x; - double y; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(exp_values); i++) { - x = exp_values[i].x; - y = exp_values[i].y; - eps = 1e-15 * exp_values[i].e; + double x = exp_values[i].x; + double e_x = exp_values[i].y; - if (fabs(exp(x) - y) > eps) - atf_tc_fail_nonfatal("exp(%0.01f) != %18.18e", x, y); + if (!(fabs((exp(x) - e_x)/e_x) <= eps)) { + atf_tc_fail_nonfatal("exp(%.17g) = %.17g != %.17g", + x, exp(x), e_x); + } } } @@ -332,18 +331,17 @@ ATF_TC_HEAD(expf_product, tc) ATF_TC_BODY(expf_product, tc) { - float eps; - float x; - float y; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(exp_values); i++) { - x = exp_values[i].x; - y = exp_values[i].y; - eps = 1e-6 * exp_values[i].e; + float x = exp_values[i].x; + float e_x = exp_values[i].y; - if (fabsf(expf(x) - y) > eps) - atf_tc_fail_nonfatal("expf(%0.01f) != %18.18e", x, y); + if (!(fabsf((expf(x) - e_x)/e_x) <= eps)) { + atf_tc_fail_nonfatal("expf(%.8g) = %.8g != %.8g", + x, exp(x), e_x); + } } } diff --git a/tests/lib/libm/t_ldexp.c b/tests/lib/libm/t_ldexp.c index 251f2aeba5fb..f6f5bb0d218c 100644 --- a/tests/lib/libm/t_ldexp.c +++ b/tests/lib/libm/t_ldexp.c @@ -35,8 +35,9 @@ __RCSID("$NetBSD: t_ldexp.c,v 1.16 2016/08/25 00:32:31 maya Exp $"); #include -#include +#include #include +#include #include #include @@ -195,22 +196,17 @@ ATF_TC_HEAD(ldexp_exp2, tc) ATF_TC_BODY(ldexp_exp2, tc) { const double n[] = { 1, 2, 3, 10, 50, 100 }; -#if __DBL_MIN_10_EXP__ <= -40 - const double eps = 1.0e-40; -#else - const double eps = __DBL_MIN__*4.0; -#endif + const double eps = DBL_EPSILON; const double x = 12.0; - double y; size_t i; for (i = 0; i < __arraycount(n); i++) { + double y = ldexp(x, n[i]); - y = ldexp(x, n[i]); - - if (fabs(y - (x * exp2(n[i]))) > eps) { - atf_tc_fail_nonfatal("ldexp(%0.01f, %0.01f) " - "!= %0.01f * exp2(%0.01f)", x, n[i], x, n[i]); + if (!(fabs((y - (x * exp2(n[i])))/y) <= eps)) { + atf_tc_fail_nonfatal("ldexp(%.17g, %.17g) = %.17g " + "!= %.17g * exp2(%.17g) = %.17g", + x, n[i], y, x, n[i], (x * exp2(n[i]))); } } } @@ -320,18 +316,17 @@ ATF_TC_HEAD(ldexpf_exp2f, tc) ATF_TC_BODY(ldexpf_exp2f, tc) { const float n[] = { 1, 2, 3, 10, 50, 100 }; - const float eps = 1.0e-9; + const float eps = FLT_EPSILON; const float x = 12.0; - float y; size_t i; for (i = 0; i < __arraycount(n); i++) { + float y = ldexpf(x, n[i]); - y = ldexpf(x, n[i]); - - if (fabsf(y - (x * exp2f(n[i]))) > eps) { - atf_tc_fail_nonfatal("ldexpf(%0.01f, %0.01f) " - "!= %0.01f * exp2f(%0.01f)", x, n[i], x, n[i]); + if (!(fabsf((y - (x * exp2f(n[i])))/y) <= eps)) { + atf_tc_fail_nonfatal("ldexpf(%.17g, %.17g) = %.17g " + "!= %.17g * exp2f(%.17g) = %.17g", + x, n[i], y, x, n[i], (x * exp2f(n[i]))); } } } diff --git a/tests/lib/libm/t_libm.h b/tests/lib/libm/t_libm.h index 34e3cb28abf5..1ed6bf8dced6 100644 --- a/tests/lib/libm/t_libm.h +++ b/tests/lib/libm/t_libm.h @@ -11,7 +11,7 @@ long double epsilon = epsilon_; \ long double expect = expect_; \ long double r = fn(arg); \ - long double e = fabsl(r - expect); \ + long double e = fabsl((r - expect)/expect); \ if (r != expect && e > epsilon) \ atf_tc_fail_nonfatal( \ "subtest %u: " #fn "(%g) is %Lg (%.14La) " \ diff --git a/tests/lib/libm/t_log.c b/tests/lib/libm/t_log.c index 756efcf39769..23b8e6a7c2d8 100644 --- a/tests/lib/libm/t_log.c +++ b/tests/lib/libm/t_log.c @@ -33,6 +33,7 @@ __RCSID("$NetBSD: t_log.c,v 1.13 2015/02/09 19:39:48 martin Exp $"); #include +#include #include #include #include @@ -614,10 +615,10 @@ ATF_TC_HEAD(log_base, tc) ATF_TC_BODY(log_base, tc) { - const double eps = 1.0e-38; + const double eps = DBL_EPSILON; - if (fabs(log(M_E) - 1.0) > eps) - atf_tc_fail_nonfatal("log(e) != 1"); + if (!(fabs(log(M_E) - 1.0) <= eps)) + atf_tc_fail_nonfatal("log(e) = %.17g != 1", log(M_E)); } ATF_TC(log_nan); @@ -714,10 +715,11 @@ ATF_TC_HEAD(logf_base, tc) ATF_TC_BODY(logf_base, tc) { - const float eps = 1.0e-7; + const float eps = FLT_EPSILON; - if (fabsf(logf(M_E) - 1.0f) > eps) - atf_tc_fail_nonfatal("logf(e) != 1"); + if (!(fabsf(logf(M_E) - 1.0f) <= eps)) + atf_tc_fail_nonfatal("logf(e) = %.17g != 1", + (double)logf(M_E)); } ATF_TC(logf_nan); diff --git a/tests/lib/libm/t_round.c b/tests/lib/libm/t_round.c index a5a930599c79..d73d92d6299e 100644 --- a/tests/lib/libm/t_round.c +++ b/tests/lib/libm/t_round.c @@ -51,9 +51,11 @@ #define SMALL_NUM 1.0e-40 #endif +#include ATF_TC(round_dir); ATF_TC_HEAD(round_dir, tc) { + fpsetprec(FP_PE); atf_tc_set_md_var(tc, "descr","Check for rounding in wrong direction"); } diff --git a/tests/lib/libm/t_scalbn.c b/tests/lib/libm/t_scalbn.c index 57970e16dbe4..4d3c96d937e7 100644 --- a/tests/lib/libm/t_scalbn.c +++ b/tests/lib/libm/t_scalbn.c @@ -97,9 +97,12 @@ ATF_TC_BODY(scalbn_val, tc) fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW), tests[i].except); #endif - ATF_CHECK_MSG(fabs(rv-tests[i].result)<2.0*DBL_EPSILON, - "test %zu: return value %g instead of %g (difference %g)", - i, rv, tests[i].result, tests[i].result-rv); + /* scalbn is always exact except for underflow or overflow. */ + ATF_CHECK_MSG(rv == tests[i].result, + "test %zu: return value %.17g instead of %.17g" + " (error %.17g)", + i, rv, tests[i].result, + fabs((tests[i].result - rv)/tests[i].result)); } } @@ -239,9 +242,12 @@ ATF_TC_BODY(scalbnf_val, tc) ATF_CHECK_EQ_MSG(errno, tests[i].error, "test %zu: errno %d instead of %d", i, errno, tests[i].error); - ATF_CHECK_MSG(fabs(rv-tests[i].result)<2.0*FLT_EPSILON, - "test %zu: return value %g instead of %g (difference %g)", - i, rv, tests[i].result, tests[i].result-rv); + /* scalbn is always exact except for underflow or overflow. */ + ATF_CHECK_MSG(rv == (float)tests[i].result, + "test %zu: return value %.8g instead of %.8g" + " (error %.8g)", + i, rv, tests[i].result, + fabsf((tests[i].result - rv)/tests[i].result)); } } @@ -384,9 +390,12 @@ ATF_TC_BODY(scalbnl_val, tc) ATF_CHECK_EQ_MSG(errno, tests[i].error, "test %zu: errno %d instead of %d", i, errno, tests[i].error); - ATF_CHECK_MSG(fabsl(rv-(long double)tests[i].result)<2.0*LDBL_EPSILON, - "test %zu: return value %Lg instead of %Lg (difference %Lg)", - i, rv, (long double)tests[i].result, (long double)tests[i].result-rv); + /* scalbn is always exact except for underflow or overflow. */ + ATF_CHECK_MSG(rv == (long double)tests[i].result, + "test %zu: return value %.35Lg instead of %.35Lg" + " (error %.35Lg)", + i, rv, (long double)tests[i].result, + fabsl(((long double)tests[i].result - rv)/tests[i].result)); } #endif } diff --git a/tests/lib/libm/t_sin.c b/tests/lib/libm/t_sin.c index a82f49dc65d6..6c1a701269c6 100644 --- a/tests/lib/libm/t_sin.c +++ b/tests/lib/libm/t_sin.c @@ -29,29 +29,39 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include +#include #include +#if defined(__i386__) || defined(__x86_64__) +const int TRIG_BUSTED = 1; +#else +const int TRIG_BUSTED = 0; +#endif + static const struct { int angle; double x; double y; + float fy; } angles[] = { - { -180, -3.141592653589793, 0.0000000000000000 }, - { -135, -2.356194490192345, -0.7071067811865476 }, - { -90, -1.570796326794897, -1.0000000000000000 }, - { -45, -0.785398163397448, -0.7071067811865476 }, - { 0, 0.000000000000000, 0.0000000000000000 }, - { 30, 0.523598775598299, 0.5000000000000000 }, - { 45, 0.785398163397448, 0.7071067811865476 }, - { 60, 1.047197551196598, 0.8660254037844386 }, - { 90, 1.570796326794897, 1.0000000000000000 }, - { 120, 2.094395102393195, 0.8660254037844386 }, - { 135, 2.356194490192345, 0.7071067811865476 }, - { 150, 2.617993877991494, 0.5000000000000000 }, - { 180, 3.141592653589793, 0.0000000000000000 }, - { 270, 4.712388980384690, -1.0000000000000000 }, - { 360, 6.283185307179586, 0.0000000000000000 } + { -360, -6.283185307179586, 2.4492935982947064e-16, -1.7484555e-07 }, + { -180, -3.141592653589793, -1.2246467991473532e-16, 8.7422777e-08 }, + { -135, -2.356194490192345, -0.7071067811865476, 999 }, + { -90, -1.570796326794897, -1.0000000000000000, 999 }, + { -45, -0.785398163397448, -0.7071067811865472, 999 }, + { 0, 0.000000000000000, 0.0000000000000000, 999 }, + { 30, 0.523598775598299, 0.5000000000000000, 999 }, + { 45, 0.785398163397448, 0.7071067811865472, 999 }, + { 60, 1.047197551196598, 0.8660254037844388, 999 }, + { 90, 1.570796326794897, 1.0000000000000000, 999 }, + { 120, 2.094395102393195, 0.8660254037844389, 999 }, + { 135, 2.356194490192345, 0.7071067811865476, 999 }, + { 150, 2.617993877991494, 0.5000000000000003, 999 }, + { 180, 3.141592653589793, 1.2246467991473532e-16, -8.7422777e-08 }, + { 270, 4.712388980384690, -1.0000000000000000, 999 }, + { 360, 6.283185307179586, -2.4492935982947064e-16, 1.7484555e-07 }, }; /* @@ -65,14 +75,36 @@ ATF_TC_HEAD(sin_angles, tc) ATF_TC_BODY(sin_angles, tc) { - const double eps = 1.0e-15; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(angles); i++) { - - if (fabs(sin(angles[i].x) - angles[i].y) > eps) - atf_tc_fail_nonfatal("sin(%d deg) != %0.01f", - angles[i].angle, angles[i].y); + int deg = angles[i].angle; + double theta = angles[i].x; + double sin_theta = angles[i].y; + bool ok; + + if (sin_theta == 0) { + /* Should be computed exactly. */ + assert(sin_theta == 0); + ok = (sin(theta) == 0); + } else { + assert(sin_theta != 0); + ok = (fabs((sin(theta) - sin_theta)/sin_theta) <= eps); + } + + if (TRIG_BUSTED && + sin_theta != 0 && + fabs(sin_theta) < 2*DBL_EPSILON) + atf_tc_expect_fail("sin near +/- pi is busted"); + if (!ok) { + atf_tc_fail_nonfatal("sin(%d deg) = %.17g != %.17g", + deg, sin(theta), sin_theta); + } + if (TRIG_BUSTED && + sin_theta != 0 && + fabs(sin_theta) < 2*DBL_EPSILON) + atf_tc_expect_pass(); } } @@ -154,18 +186,30 @@ ATF_TC_HEAD(sinf_angles, tc) ATF_TC_BODY(sinf_angles, tc) { - const float eps = 1.0e-6; - float x, y; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(angles); i++) { - - x = angles[i].x; - y = angles[i].y; - - if (fabsf(sinf(x) - y) > eps) - atf_tc_fail_nonfatal("sinf(%d deg) != %0.01f", - angles[i].angle, angles[i].y); + int deg = angles[i].angle; + float theta = angles[i].x; + float sin_theta = angles[i].fy; + bool ok; + + if (sin_theta == 999) + sin_theta = angles[i].y; + + if (sin_theta == 0) { + /* Should be computed exactly. */ + ok = (sinf(theta) == 0); + } else { + ok = (fabsf((sinf(theta) - sin_theta)/sin_theta) + <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("sinf(%d deg) = %.17g != %.17g", + deg, (double)sin(theta), (double)sin_theta); + } } } diff --git a/tests/lib/libm/t_sinh.c b/tests/lib/libm/t_sinh.c index d935f0ea7ffb..8205e97840e7 100644 --- a/tests/lib/libm/t_sinh.c +++ b/tests/lib/libm/t_sinh.c @@ -32,24 +32,24 @@ __RCSID("$NetBSD: t_sinh.c,v 1.6 2014/03/03 10:39:08 martin Exp $"); #include +#include #include #include static const struct { double x; double y; - double e; } values[] = { - { -10, -11013.23287470339, 1e4, }, - { -2, -3.626860407847019, 1, }, - { -1, -1.175201193643801, 1, }, - { -0.05, -0.050020835937655, 1, }, - { -0.001,-0.001000000166667, 1, }, - { 0.001, 0.001000000166667, 1, }, - { 0.05, 0.050020835937655, 1, }, - { 1, 1.175201193643801, 1, }, - { 2, 3.626860407847019, 1, }, - { 10, 11013.23287470339, 1e4, }, + { -10, -11013.232874703393, }, + { -2, -3.626860407847019, }, + { -1, -1.1752011936438014, }, + { -0.05, -0.050020835937655016, }, + { -0.001,-0.0010000001666666751, }, + { 0.001, 0.0010000001666666751, }, + { 0.05, 0.050020835937655016, }, + { 1, 1.1752011936438014, }, + { 2, 3.626860407847019, }, + { 10, 11013.232874703393, }, }; /* @@ -63,18 +63,17 @@ ATF_TC_HEAD(sinh_inrange, tc) ATF_TC_BODY(sinh_inrange, tc) { - double eps; - double x; - double y; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(values); i++) { - x = values[i].x; - y = values[i].y; - eps = 1e-15 * values[i].e; + double x = values[i].x; + double sinh_x = values[i].y; - if (fabs(sinh(x) - y) > eps) - atf_tc_fail_nonfatal("sinh(%g) != %g\n", x, y); + if (!(fabs((sinh(x) - sinh_x)/sinh_x) <= eps)) { + atf_tc_fail_nonfatal("sinh(%.17g) = %.17g != %.17g\n", + x, sinh(x), sinh_x); + } } } @@ -163,18 +162,17 @@ ATF_TC_HEAD(sinhf_inrange, tc) ATF_TC_BODY(sinhf_inrange, tc) { - float eps; - float x; - float y; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(values); i++) { - x = values[i].x; - y = values[i].y; - eps = 1e-6 * values[i].e; + float x = values[i].x; + float sinh_x = values[i].y; - if (fabsf(sinhf(x) - y) > eps) - atf_tc_fail_nonfatal("sinhf(%g) != %g\n", x, y); + if (!(fabsf((sinhf(x) - sinh_x)/sinh_x) <= eps)) { + atf_tc_fail_nonfatal("sinhf(%.8g) = %.8g != %.8g\n", + (double)x, (double)sinhf(x), (double)sinh_x); + } } } diff --git a/tests/lib/libm/t_sqrt.c b/tests/lib/libm/t_sqrt.c index 1d551ec3101d..d1da31477160 100644 --- a/tests/lib/libm/t_sqrt.c +++ b/tests/lib/libm/t_sqrt.c @@ -62,22 +62,25 @@ ATF_TC_HEAD(sqrt_pow, tc) ATF_TC_BODY(sqrt_pow, tc) { const double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.9999 }; -#if __DBL_MIN_10_EXP__ <= -40 - const double eps = 1.0e-40; -#else - const double eps = __DBL_MIN__*4.0; -#endif - double y, z; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(x); i++) { - - y = sqrt(x[i]); - z = pow(x[i], 1.0 / 2.0); - - if (fabs(y - z) > eps) - atf_tc_fail_nonfatal("sqrt(%0.03f) != " - "pow(%0.03f, 1/2)\n", x[i], x[i]); + double x_sqrt = sqrt(x[i]); + double x_pow12 = pow(x[i], 1.0 / 2.0); + bool ok; + + if (x[i] == 0) { + ok = (x_sqrt == x_pow12); + } else { + ok = (fabs((x_sqrt - x_pow12)/x_sqrt) <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("sqrt(%.17g) = %.17g != " + "pow(%.17g, 1/2) = %.17g\n", + x[i], x_sqrt, x[i], x_pow12); + } } } @@ -166,18 +169,26 @@ ATF_TC_HEAD(sqrtf_powf, tc) ATF_TC_BODY(sqrtf_powf, tc) { const float x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.9999 }; - const float eps = 1.0e-30; - volatile float y, z; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(x); i++) { - - y = sqrtf(x[i]); - z = powf(x[i], 1.0 / 2.0); - - if (fabsf(y - z) > eps) - atf_tc_fail_nonfatal("sqrtf(%0.03f) != " - "powf(%0.03f, 1/2)\n", x[i], x[i]); + float x_sqrt = sqrtf(x[i]); + float x_pow12 = powf(x[i], 1.0 / 2.0); + bool ok; + + if (x[i] == 0) { + ok = (x_sqrt == x_pow12); + } else { + ok = (fabsf((x_sqrt - x_pow12)/x_sqrt) <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("sqrtf(%.8g) = %.8g != " + "powf(%.8g, 1/2) = %.8g\n", + (double)x[i], (double)x_sqrt, + (double)x[i], (double)x_pow12); + } } } @@ -266,18 +277,25 @@ ATF_TC_HEAD(sqrtl_powl, tc) ATF_TC_BODY(sqrtl_powl, tc) { const long double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.9999 }; - const long double eps = 5.0*DBL_EPSILON; /* XXX powl == pow for now */ - volatile long double y, z; + const long double eps = DBL_EPSILON; /* XXX powl == pow for now */ size_t i; for (i = 0; i < __arraycount(x); i++) { - - y = sqrtl(x[i]); - z = powl(x[i], 1.0 / 2.0); - - if (fabsl(y - z) > eps) - atf_tc_fail_nonfatal("sqrtl(%0.03Lf) != " - "powl(%0.03Lf, 1/2)\n", x[i], x[i]); + long double x_sqrt = sqrtl(x[i]); + long double x_pow12 = powl(x[i], 1.0 / 2.0); + bool ok; + + if (x[i] == 0) { + ok = (x_sqrt == x_pow12); + } else { + ok = (fabsl((x_sqrt - x_pow12)/x_sqrt) <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("sqrtl(%.35Lg) = %.35Lg != " + "powl(%.35Lg, 1/2) = %.35Lg\n", + x[i], x_sqrt, x[i], x_pow12); + } } } diff --git a/tests/lib/libm/t_tan.c b/tests/lib/libm/t_tan.c index 807e3d1f3364..5e72f1bf64e1 100644 --- a/tests/lib/libm/t_tan.c +++ b/tests/lib/libm/t_tan.c @@ -29,26 +29,35 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include +#include #include +#if defined(__i386__) || defined(__x86_64__) +const int TRIG_BUSTED = 1; +#else +const int TRIG_BUSTED = 0; +#endif + static const struct { int angle; double x; double y; + float fy; } angles[] = { - { -180, -3.141592653589793, 0.0000000000000000 }, - { -135, -2.356194490192345, 1.0000000000000000 }, - { -45, -0.785398163397448, -1.0000000000000000 }, - { 0, 0.000000000000000, 0.0000000000000000 }, - { 30, 0.523598775598299, 0.5773502691896258 }, - { 45, 0.785398163397448, 1.0000000000000000 }, - { 60, 1.047197551196598, 1.7320508075688773 }, - { 120, 2.094395102393195, -1.7320508075688773 }, - { 135, 2.356194490192345, -1.0000000000000000 }, - { 150, 2.617993877991494, -0.5773502691896258 }, - { 180, 3.141592653589793, 0.0000000000000000 }, - { 360, 6.283185307179586, 0.0000000000000000 } + { -180, -3.141592653589793, 1.2246467991473532e-16, -8.7422777e-08 }, + { -135, -2.356194490192345, 1.0000000000000002, 999 }, + { -45, -0.785398163397448, -0.9999999999999992, 999 }, + { 0, 0.000000000000000, 0.0000000000000000, 999 }, + { 30, 0.523598775598299, 0.5773502691896258, 999 }, + { 45, 0.785398163397448, 0.9999999999999992, 999 }, + { 60, 1.047197551196598, 1.7320508075688785, 999 }, + { 120, 2.094395102393195, -1.7320508075688801, -1.7320505 }, + { 135, 2.356194490192345, -1.0000000000000002, 999 }, + { 150, 2.617993877991494, -0.5773502691896263, 999 }, + { 180, 3.141592653589793, -1.2246467991473532e-16, 8.7422777e-08 }, + { 360, 6.283185307179586, -2.4492935982947064e-16, 1.7484555e-07 }, }; /* @@ -62,14 +71,36 @@ ATF_TC_HEAD(tan_angles, tc) ATF_TC_BODY(tan_angles, tc) { - const double eps = 1.0e-14; + const double eps = DBL_EPSILON; size_t i; for (i = 0; i < __arraycount(angles); i++) { - - if (fabs(tan(angles[i].x) - angles[i].y) > eps) - atf_tc_fail_nonfatal("tan(%d deg) != %0.01f", - angles[i].angle, angles[i].y); + int deg = angles[i].angle; + double theta = angles[i].x; + double tan_theta = angles[i].y; + bool ok; + + if (theta == 0) { + /* Should be computed exactly. */ + assert(tan_theta == 0); + ok = (tan(theta) == 0); + } else { + assert(tan_theta != 0); + ok = (fabs((tan(theta) - tan_theta)/tan_theta) <= eps); + } + + if (TRIG_BUSTED && + tan_theta != 0 && + fabs(tan_theta) < 2*DBL_EPSILON) + atf_tc_expect_fail("tan near +/- pi is busted"); + if (!ok) { + atf_tc_fail_nonfatal("tan(%d deg) = %.17g != %.17g", + deg, tan(theta), tan_theta); + } + if (TRIG_BUSTED && + tan_theta != 0 && + fabs(tan_theta) < 2*DBL_EPSILON) + atf_tc_expect_pass(); } } @@ -151,18 +182,32 @@ ATF_TC_HEAD(tanf_angles, tc) ATF_TC_BODY(tanf_angles, tc) { - const float eps = 1.0e-6; - float x, y; + const float eps = FLT_EPSILON; size_t i; for (i = 0; i < __arraycount(angles); i++) { - - x = angles[i].x; - y = angles[i].y; - - if (fabsf(tanf(x) - y) > eps) - atf_tc_fail_nonfatal("tanf(%d deg) != %0.01f", - angles[i].angle, angles[i].y); + int deg = angles[i].angle; + float theta = angles[i].x; + float tan_theta = angles[i].fy; + bool ok; + + if (tan_theta == 999) + tan_theta = angles[i].y; + + if (theta == 0) { + /* Should be computed exactly. */ + assert(tan_theta == 0); + ok = (tan(theta) == 0); + } else { + assert(tan_theta != 0); + ok = (fabsf((tanf(theta) - tan_theta)/tan_theta) + <= eps); + } + + if (!ok) { + atf_tc_fail_nonfatal("tanf(%d deg) = %.8g != %.8g", + deg, tanf(theta), tan_theta); + } } }