Changeset View
Changeset View
Standalone View
Standalone View
lib/msun/tests/invtrig_test.c
Show All 27 Lines | |||||
* Tests for corner cases in the inverse trigonometric functions. Some | * Tests for corner cases in the inverse trigonometric functions. Some | ||||
* accuracy tests are included as well, but these are very basic | * accuracy tests are included as well, but these are very basic | ||||
* sanity checks, not intended to be comprehensive. | * sanity checks, not intended to be comprehensive. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <assert.h> | |||||
#include <fenv.h> | #include <fenv.h> | ||||
#include <float.h> | #include <float.h> | ||||
#include <math.h> | #include <math.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include "test-utils.h" | #include "test-utils.h" | ||||
#pragma STDC FENV_ACCESS ON | #pragma STDC FENV_ACCESS ON | ||||
/* | /* | ||||
* Test that a function returns the correct value and sets the | * Test that a function returns the correct value and sets the | ||||
* exception flags correctly. A tolerance specifying the maximum | * exception flags correctly. A tolerance specifying the maximum | ||||
* relative error allowed may be specified. For the 'testall' | * relative error allowed may be specified. For the 'testall' | ||||
* functions, the tolerance is specified in ulps. | * functions, the tolerance is specified in ulps. | ||||
* | * | ||||
* These are macros instead of functions so that assert provides more | * These are macros instead of functions so that assert provides more | ||||
* meaningful error messages. | * meaningful error messages. | ||||
*/ | */ | ||||
#define test_tol(func, x, result, tol, excepts) do { \ | #define test_tol(func, x, result, tol, excepts) do { \ | ||||
volatile long double _in = (x), _out = (result); \ | volatile long double _in = (x), _out = (result); \ | ||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \ | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ | ||||
assert(fpequal_tol(func(_in), _out, (tol), CS_BOTH)); \ | ATF_CHECK(fpequal_tol(func(_in), _out, (tol), CS_BOTH)); \ | ||||
assert(((void)func, fetestexcept(ALL_STD_EXCEPT) == (excepts))); \ | CHECK_FP_EXCEPTIONS_MSG(excepts, ALL_STD_EXCEPT, "for %s(%s)", \ | ||||
#func, #x); \ | |||||
} while (0) | } while (0) | ||||
#define test(func, x, result, excepts) \ | #define test(func, x, result, excepts) \ | ||||
test_tol(func, (x), (result), 0, (excepts)) | test_tol(func, (x), (result), 0, (excepts)) | ||||
#define _testall_tol(prefix, x, result, tol, excepts) do { \ | #define _testall_tol(prefix, x, result, tol, excepts) do { \ | ||||
test_tol(prefix, (double)(x), (double)(result), \ | test_tol(prefix, (double)(x), (double)(result), \ | ||||
(tol) * ldexp(1.0, 1 - DBL_MANT_DIG), (excepts)); \ | (tol) * ldexp(1.0, 1 - DBL_MANT_DIG), (excepts)); \ | ||||
test_tol(prefix##f, (float)(x), (float)(result), \ | test_tol(prefix##f, (float)(x), (float)(result), \ | ||||
Show All 10 Lines | |||||
} while (0) | } while (0) | ||||
#endif | #endif | ||||
#define testall(prefix, x, result, excepts) \ | #define testall(prefix, x, result, excepts) \ | ||||
testall_tol(prefix, (x), (result), 0, (excepts)) | testall_tol(prefix, (x), (result), 0, (excepts)) | ||||
#define test2_tol(func, y, x, result, tol, excepts) do { \ | #define test2_tol(func, y, x, result, tol, excepts) do { \ | ||||
volatile long double _iny = (y), _inx = (x), _out = (result); \ | volatile long double _iny = (y), _inx = (x), _out = (result); \ | ||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \ | ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ | ||||
assert(fpequal_tol(func(_iny, _inx), _out, (tol), CS_BOTH)); \ | ATF_CHECK(fpequal_tol(func(_iny, _inx), _out, (tol), CS_BOTH)); \ | ||||
assert(((void)func, fetestexcept(ALL_STD_EXCEPT) == (excepts))); \ | CHECK_FP_EXCEPTIONS_MSG(excepts, ALL_STD_EXCEPT, "for %s(%s)", \ | ||||
#func, #x); \ | |||||
} while (0) | } while (0) | ||||
#define test2(func, y, x, result, excepts) \ | #define test2(func, y, x, result, excepts) \ | ||||
test2_tol(func, (y), (x), (result), 0, (excepts)) | test2_tol(func, (y), (x), (result), 0, (excepts)) | ||||
#define _testall2_tol(prefix, y, x, result, tol, excepts) do { \ | #define _testall2_tol(prefix, y, x, result, tol, excepts) do { \ | ||||
test2_tol(prefix, (double)(y), (double)(x), (double)(result), \ | test2_tol(prefix, (double)(y), (double)(x), (double)(result), \ | ||||
(tol) * ldexp(1.0, 1 - DBL_MANT_DIG), (excepts)); \ | (tol) * ldexp(1.0, 1 - DBL_MANT_DIG), (excepts)); \ | ||||
test2_tol(prefix##f, (float)(y), (float)(x), (float)(result), \ | test2_tol(prefix##f, (float)(y), (float)(x), (float)(result), \ | ||||
Show All 21 Lines | |||||
c5pio3 = 5.23598775598298873077107230546583851e+00L, | c5pio3 = 5.23598775598298873077107230546583851e+00L, | ||||
sqrt2m1 = 4.14213562373095048801688724209698081e-01L; | sqrt2m1 = 4.14213562373095048801688724209698081e-01L; | ||||
/* | /* | ||||
* Test special case inputs in asin(), acos() and atan(): signed | * Test special case inputs in asin(), acos() and atan(): signed | ||||
* zeroes, infinities, and NaNs. | * zeroes, infinities, and NaNs. | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(special); | ||||
test_special(void) | ATF_TC_BODY(special, tc) | ||||
{ | { | ||||
testall(asin, 0.0, 0.0, 0); | testall(asin, 0.0, 0.0, 0); | ||||
testall(acos, 0.0, pi / 2, FE_INEXACT); | testall(acos, 0.0, pi / 2, FE_INEXACT); | ||||
testall(atan, 0.0, 0.0, 0); | testall(atan, 0.0, 0.0, 0); | ||||
testall(asin, -0.0, -0.0, 0); | testall(asin, -0.0, -0.0, 0); | ||||
testall(acos, -0.0, pi / 2, FE_INEXACT); | testall(acos, -0.0, pi / 2, FE_INEXACT); | ||||
testall(atan, -0.0, -0.0, 0); | testall(atan, -0.0, -0.0, 0); | ||||
Show All 9 Lines | ATF_TC_BODY(special, tc) | ||||
testall(acos, NAN, NAN, 0); | testall(acos, NAN, NAN, 0); | ||||
testall(atan, NAN, NAN, 0); | testall(atan, NAN, NAN, 0); | ||||
} | } | ||||
/* | /* | ||||
* Test special case inputs in atan2(), where the exact value of y/x is | * Test special case inputs in atan2(), where the exact value of y/x is | ||||
* zero or non-finite. | * zero or non-finite. | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(special_atan2); | ||||
test_special_atan2(void) | ATF_TC_BODY(special_atan2, tc) | ||||
{ | { | ||||
long double z; | long double z; | ||||
int e; | int e; | ||||
testall2(atan2, 0.0, -0.0, pi, FE_INEXACT); | testall2(atan2, 0.0, -0.0, pi, FE_INEXACT); | ||||
testall2(atan2, -0.0, -0.0, -pi, FE_INEXACT); | testall2(atan2, -0.0, -0.0, -pi, FE_INEXACT); | ||||
testall2(atan2, 0.0, 0.0, 0.0, 0); | testall2(atan2, 0.0, 0.0, 0.0, 0); | ||||
testall2(atan2, -0.0, 0.0, -0.0, 0); | testall2(atan2, -0.0, 0.0, -0.0, 0); | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | for (e = LDBL_MIN_EXP - LDBL_MANT_DIG; e <= LDBL_MAX_EXP - 1; e++) { | ||||
test2(atan2l, -INFINITY, ldexpl(-z, e), -pi / 2, FE_INEXACT); | test2(atan2l, -INFINITY, ldexpl(-z, e), -pi / 2, FE_INEXACT); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Test various inputs to asin(), acos() and atan() and verify that the | * Test various inputs to asin(), acos() and atan() and verify that the | ||||
* results are accurate to within 1 ulp. | * results are accurate to within 1 ulp. | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(accuracy); | ||||
test_accuracy(void) | ATF_TC_BODY(accuracy, tc) | ||||
{ | { | ||||
/* We expect correctly rounded results for these basic cases. */ | /* We expect correctly rounded results for these basic cases. */ | ||||
testall(asin, 1.0, pi / 2, FE_INEXACT); | testall(asin, 1.0, pi / 2, FE_INEXACT); | ||||
testall(acos, 1.0, 0, 0); | testall(acos, 1.0, 0, 0); | ||||
testall(atan, 1.0, pi / 4, FE_INEXACT); | testall(atan, 1.0, pi / 4, FE_INEXACT); | ||||
testall(asin, -1.0, -pi / 2, FE_INEXACT); | testall(asin, -1.0, -pi / 2, FE_INEXACT); | ||||
testall(acos, -1.0, pi, FE_INEXACT); | testall(acos, -1.0, pi, FE_INEXACT); | ||||
Show All 20 Lines | ATF_TC_BODY(accuracy, tc) | ||||
testall_tol(atan, sqrt2m1, pi / 8, 1, FE_INEXACT); | testall_tol(atan, sqrt2m1, pi / 8, 1, FE_INEXACT); | ||||
testall_tol(atan, -sqrt2m1, -pi / 8, 1, FE_INEXACT); | testall_tol(atan, -sqrt2m1, -pi / 8, 1, FE_INEXACT); | ||||
} | } | ||||
/* | /* | ||||
* Test inputs to atan2() where x is a power of 2. These are easy cases | * Test inputs to atan2() where x is a power of 2. These are easy cases | ||||
* because y/x is exact. | * because y/x is exact. | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(p2x_atan2); | ||||
test_p2x_atan2(void) | ATF_TC_BODY(p2x_atan2, tc) | ||||
{ | { | ||||
testall2(atan2, 1.0, 1.0, pi / 4, FE_INEXACT); | testall2(atan2, 1.0, 1.0, pi / 4, FE_INEXACT); | ||||
testall2(atan2, 1.0, -1.0, c3pi / 4, FE_INEXACT); | testall2(atan2, 1.0, -1.0, c3pi / 4, FE_INEXACT); | ||||
testall2(atan2, -1.0, 1.0, -pi / 4, FE_INEXACT); | testall2(atan2, -1.0, 1.0, -pi / 4, FE_INEXACT); | ||||
testall2(atan2, -1.0, -1.0, -c3pi / 4, FE_INEXACT); | testall2(atan2, -1.0, -1.0, -c3pi / 4, FE_INEXACT); | ||||
testall2_tol(atan2, sqrt2m1 * 2, 2.0, pi / 8, 1, FE_INEXACT); | testall2_tol(atan2, sqrt2m1 * 2, 2.0, pi / 8, 1, FE_INEXACT); | ||||
testall2_tol(atan2, sqrt2m1 * 2, -2.0, c7pi / 8, 1, FE_INEXACT); | testall2_tol(atan2, sqrt2m1 * 2, -2.0, c7pi / 8, 1, FE_INEXACT); | ||||
testall2_tol(atan2, -sqrt2m1 * 2, 2.0, -pi / 8, 1, FE_INEXACT); | testall2_tol(atan2, -sqrt2m1 * 2, 2.0, -pi / 8, 1, FE_INEXACT); | ||||
testall2_tol(atan2, -sqrt2m1 * 2, -2.0, -c7pi / 8, 1, FE_INEXACT); | testall2_tol(atan2, -sqrt2m1 * 2, -2.0, -c7pi / 8, 1, FE_INEXACT); | ||||
testall2_tol(atan2, sqrtl(3) * 0.5, 0.5, pio3, 1, FE_INEXACT); | testall2_tol(atan2, sqrtl(3) * 0.5, 0.5, pio3, 1, FE_INEXACT); | ||||
testall2_tol(atan2, sqrtl(3) * 0.5, -0.5, pio3 * 2, 1, FE_INEXACT); | testall2_tol(atan2, sqrtl(3) * 0.5, -0.5, pio3 * 2, 1, FE_INEXACT); | ||||
testall2_tol(atan2, -sqrtl(3) * 0.5, 0.5, -pio3, 1, FE_INEXACT); | testall2_tol(atan2, -sqrtl(3) * 0.5, 0.5, -pio3, 1, FE_INEXACT); | ||||
testall2_tol(atan2, -sqrtl(3) * 0.5, -0.5, -pio3 * 2, 1, FE_INEXACT); | testall2_tol(atan2, -sqrtl(3) * 0.5, -0.5, -pio3 * 2, 1, FE_INEXACT); | ||||
} | } | ||||
/* | /* | ||||
* Test inputs very close to 0. | * Test inputs very close to 0. | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(tiny); | ||||
test_tiny(void) | ATF_TC_BODY(tiny, tc) | ||||
{ | { | ||||
float tiny = 0x1.23456p-120f; | float tiny = 0x1.23456p-120f; | ||||
testall(asin, tiny, tiny, FE_INEXACT); | testall(asin, tiny, tiny, FE_INEXACT); | ||||
testall(acos, tiny, pi / 2, FE_INEXACT); | testall(acos, tiny, pi / 2, FE_INEXACT); | ||||
testall(atan, tiny, tiny, FE_INEXACT); | testall(atan, tiny, tiny, FE_INEXACT); | ||||
testall(asin, -tiny, -tiny, FE_INEXACT); | testall(asin, -tiny, -tiny, FE_INEXACT); | ||||
Show All 17 Lines | ATF_TC_BODY(tiny, tc) | ||||
test2(atan2, -0x1.0p-1000, -0x1.0p1000, (double)-pi, FE_INEXACT); | test2(atan2, -0x1.0p-1000, -0x1.0p1000, (double)-pi, FE_INEXACT); | ||||
test2(atan2l, -ldexpl(1.0, 100 - LDBL_MAX_EXP), | test2(atan2l, -ldexpl(1.0, 100 - LDBL_MAX_EXP), | ||||
-ldexpl(1.0, LDBL_MAX_EXP - 100), -pi, FE_INEXACT); | -ldexpl(1.0, LDBL_MAX_EXP - 100), -pi, FE_INEXACT); | ||||
} | } | ||||
/* | /* | ||||
* Test very large inputs to atan(). | * Test very large inputs to atan(). | ||||
*/ | */ | ||||
static void | ATF_TC_WITHOUT_HEAD(atan_huge); | ||||
test_atan_huge(void) | ATF_TC_BODY(atan_huge, tc) | ||||
{ | { | ||||
float huge = 0x1.23456p120; | float huge = 0x1.23456p120; | ||||
testall(atan, huge, pi / 2, FE_INEXACT); | testall(atan, huge, pi / 2, FE_INEXACT); | ||||
testall(atan, -huge, -pi / 2, FE_INEXACT); | testall(atan, -huge, -pi / 2, FE_INEXACT); | ||||
/* Test inputs to atan2() that would cause y/x to overflow. */ | /* Test inputs to atan2() that would cause y/x to overflow. */ | ||||
test2(atan2f, 0x1.0p100, 0x1.0p-100, (float)pi / 2, FE_INEXACT); | test2(atan2f, 0x1.0p100, 0x1.0p-100, (float)pi / 2, FE_INEXACT); | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | |||||
static long double | static long double | ||||
tanatanl(long double x) | tanatanl(long double x) | ||||
{ | { | ||||
return (tanl(atanl(x))); | return (tanl(atanl(x))); | ||||
} | } | ||||
static void | ATF_TC_WITHOUT_HEAD(inverse); | ||||
test_inverse(void) | ATF_TC_BODY(inverse, tc) | ||||
{ | { | ||||
float i; | float i; | ||||
for (i = -1; i <= 1; i += 0x1.0p-12f) { | for (i = -1; i <= 1; i += 0x1.0p-12f) { | ||||
testall_tol(sinasin, i, i, 2, i == 0 ? 0 : FE_INEXACT); | testall_tol(sinasin, i, i, 2, i == 0 ? 0 : FE_INEXACT); | ||||
/* The relative error for cosacos is very large near x=0. */ | /* The relative error for cosacos is very large near x=0. */ | ||||
if (fabsf(i) > 0x1.0p-4f) | if (fabsf(i) > 0x1.0p-4f) | ||||
testall_tol(cosacos, i, i, 16, i == 1 ? 0 : FE_INEXACT); | testall_tol(cosacos, i, i, 16, i == 1 ? 0 : FE_INEXACT); | ||||
testall_tol(tanatan, i, i, 2, i == 0 ? 0 : FE_INEXACT); | testall_tol(tanatan, i, i, 2, i == 0 ? 0 : FE_INEXACT); | ||||
} | } | ||||
} | } | ||||
int | ATF_TP_ADD_TCS(tp) | ||||
main(void) | |||||
{ | { | ||||
ATF_TP_ADD_TC(tp, special); | |||||
ATF_TP_ADD_TC(tp, special_atan2); | |||||
ATF_TP_ADD_TC(tp, accuracy); | |||||
ATF_TP_ADD_TC(tp, p2x_atan2); | |||||
ATF_TP_ADD_TC(tp, tiny); | |||||
ATF_TP_ADD_TC(tp, atan_huge); | |||||
ATF_TP_ADD_TC(tp, inverse); | |||||
ngie: newline | |||||
#if defined(__i386__) | return (atf_no_error()); | ||||
printf("1..0 # SKIP fails all assertions on i386\n"); | |||||
return (0); | |||||
#endif | |||||
printf("1..7\n"); | |||||
test_special(); | |||||
printf("ok 1 - special\n"); | |||||
test_special_atan2(); | |||||
printf("ok 2 - atan2 special\n"); | |||||
test_accuracy(); | |||||
printf("ok 3 - accuracy\n"); | |||||
test_p2x_atan2(); | |||||
printf("ok 4 - atan2 p2x\n"); | |||||
test_tiny(); | |||||
printf("ok 5 - tiny inputs\n"); | |||||
test_atan_huge(); | |||||
printf("ok 6 - atan huge inputs\n"); | |||||
test_inverse(); | |||||
printf("ok 7 - inverse\n"); | |||||
return (0); | |||||
} | } |
newline