Factor out some common code from the libm tests. This is a bit messy
because different tests have different ideas about what it means to be "close enough" to the right answer, depending on the properties of the function being tested. In the process, I fixed some warnings and added a few more 'volatile' hacks, which are sufficient to make all the tests pass at -O2 with clang.
This commit is contained in:
parent
950ff8e4dd
commit
45de1d006d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=251241
@ -5,7 +5,7 @@ TESTS= test-cexp test-conj test-csqrt test-ctrig \
|
||||
test-fmaxmin test-ilogb test-invtrig test-invctrig \
|
||||
test-logarithm test-lrint \
|
||||
test-lround test-nan test-nearbyint test-next test-rem test-trig
|
||||
CFLAGS+= -O0 -lm
|
||||
CFLAGS+= -O0 -lm -Wno-unknown-pragmas
|
||||
|
||||
.PHONY: tests
|
||||
tests: ${TESTS}
|
||||
|
@ -38,34 +38,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#define FLT_ULP() ldexpl(1.0, 1 - FLT_MANT_DIG)
|
||||
#define DBL_ULP() ldexpl(1.0, 1 - DBL_MANT_DIG)
|
||||
#define LDBL_ULP() ldexpl(1.0, 1 - LDBL_MANT_DIG)
|
||||
#include "test-utils.h"
|
||||
|
||||
#define N(i) (sizeof(i) / sizeof((i)[0]))
|
||||
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#pragma STDC CX_LIMITED_RANGE OFF
|
||||
|
||||
/*
|
||||
* XXX gcc implements complex multiplication incorrectly. In
|
||||
* particular, it implements it as if the CX_LIMITED_RANGE pragma
|
||||
* were ON. Consequently, we need this function to form numbers
|
||||
* such as x + INFINITY * I, since gcc evalutes INFINITY * I as
|
||||
* NaN + INFINITY * I.
|
||||
*/
|
||||
static inline long double complex
|
||||
cpackl(long double x, long double y)
|
||||
{
|
||||
long double complex z;
|
||||
|
||||
__real__ z = x;
|
||||
__imag__ z = y;
|
||||
return (z);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a function returns the correct value and sets the
|
||||
* exception flags correctly. The exceptmask specifies which
|
||||
@ -83,14 +62,15 @@ cpackl(long double x, long double y)
|
||||
#define test(func, z, result, exceptmask, excepts, checksign) do { \
|
||||
volatile long double complex _d = z; \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(cfpequal((func)(_d), (result), (checksign))); \
|
||||
assert(((func), fetestexcept(exceptmask) == (excepts))); \
|
||||
assert(cfpequal_cs((func)(_d), (result), (checksign))); \
|
||||
assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
|
||||
} while (0)
|
||||
|
||||
/* Test within a given tolerance. */
|
||||
#define test_tol(func, z, result, tol) do { \
|
||||
volatile long double complex _d = z; \
|
||||
assert(cfpequal_tol((func)(_d), (result), (tol))); \
|
||||
assert(cfpequal_tol((func)(_d), (result), (tol), \
|
||||
FPE_ABS_ZERO | CS_BOTH)); \
|
||||
} while (0)
|
||||
|
||||
/* Test all the functions that compute cexp(x). */
|
||||
@ -112,67 +92,6 @@ cpackl(long double x, long double y)
|
||||
static const float finites[] =
|
||||
{ -42.0e20, -1.0, -1.0e-10, -0.0, 0.0, 1.0e-10, 1.0, 42.0e20 };
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
* If checksign is 0, we compare the absolute values instead.
|
||||
*/
|
||||
static int
|
||||
fpequal(long double x, long double y, int checksign)
|
||||
{
|
||||
if (isnan(x) || isnan(y))
|
||||
return (1);
|
||||
if (checksign)
|
||||
return (x == y && !signbit(x) == !signbit(y));
|
||||
else
|
||||
return (fabsl(x) == fabsl(y));
|
||||
}
|
||||
|
||||
static int
|
||||
fpequal_tol(long double x, long double y, long double tol)
|
||||
{
|
||||
fenv_t env;
|
||||
int ret;
|
||||
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (!signbit(x) != !signbit(y))
|
||||
return (0);
|
||||
if (x == y)
|
||||
return (1);
|
||||
if (tol == 0)
|
||||
return (0);
|
||||
|
||||
/* Hard case: need to check the tolerance. */
|
||||
feholdexcept(&env);
|
||||
/*
|
||||
* For our purposes here, if y=0, we interpret tol as an absolute
|
||||
* tolerance. This is to account for roundoff in the input, e.g.,
|
||||
* cos(Pi/2) ~= 0.
|
||||
*/
|
||||
if (y == 0.0)
|
||||
ret = fabsl(x - y) <= fabsl(tol);
|
||||
else
|
||||
ret = fabsl(x - y) <= fabsl(y * tol);
|
||||
fesetenv(&env);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal(long double complex x, long double complex y, int checksign)
|
||||
{
|
||||
return (fpequal(creal(x), creal(y), checksign)
|
||||
&& fpequal(cimag(x), cimag(y), checksign));
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal_tol(long double complex x, long double complex y, long double tol)
|
||||
{
|
||||
return (fpequal_tol(creal(x), creal(y), tol)
|
||||
&& fpequal_tol(cimag(x), cimag(y), tol));
|
||||
}
|
||||
|
||||
|
||||
/* Tests for 0 */
|
||||
void
|
||||
@ -182,8 +101,8 @@ test_zero(void)
|
||||
/* cexp(0) = 1, no exceptions raised */
|
||||
testall(0.0, 1.0, ALL_STD_EXCEPT, 0, 1);
|
||||
testall(-0.0, 1.0, ALL_STD_EXCEPT, 0, 1);
|
||||
testall(cpackl(0.0, -0.0), cpackl(1.0, -0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
testall(cpackl(-0.0, -0.0), cpackl(1.0, -0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
testall(CMPLXL(0.0, -0.0), CMPLXL(1.0, -0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
testall(CMPLXL(-0.0, -0.0), CMPLXL(1.0, -0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -198,27 +117,27 @@ test_nan()
|
||||
/* cexp(x + NaNi) = NaN + NaNi and optionally raises invalid */
|
||||
/* cexp(NaN + yi) = NaN + NaNi and optionally raises invalid (|y|>0) */
|
||||
for (i = 0; i < N(finites); i++) {
|
||||
testall(cpackl(finites[i], NAN), cpackl(NAN, NAN),
|
||||
testall(CMPLXL(finites[i], NAN), CMPLXL(NAN, NAN),
|
||||
ALL_STD_EXCEPT & ~FE_INVALID, 0, 0);
|
||||
if (finites[i] == 0.0)
|
||||
continue;
|
||||
/* XXX FE_INEXACT shouldn't be raised here */
|
||||
testall(cpackl(NAN, finites[i]), cpackl(NAN, NAN),
|
||||
testall(CMPLXL(NAN, finites[i]), CMPLXL(NAN, NAN),
|
||||
ALL_STD_EXCEPT & ~(FE_INVALID | FE_INEXACT), 0, 0);
|
||||
}
|
||||
|
||||
/* cexp(NaN +- 0i) = NaN +- 0i */
|
||||
testall(cpackl(NAN, 0.0), cpackl(NAN, 0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
testall(cpackl(NAN, -0.0), cpackl(NAN, -0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
testall(CMPLXL(NAN, 0.0), CMPLXL(NAN, 0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
testall(CMPLXL(NAN, -0.0), CMPLXL(NAN, -0.0), ALL_STD_EXCEPT, 0, 1);
|
||||
|
||||
/* cexp(inf + NaN i) = inf + nan i */
|
||||
testall(cpackl(INFINITY, NAN), cpackl(INFINITY, NAN),
|
||||
testall(CMPLXL(INFINITY, NAN), CMPLXL(INFINITY, NAN),
|
||||
ALL_STD_EXCEPT, 0, 0);
|
||||
/* cexp(-inf + NaN i) = 0 */
|
||||
testall(cpackl(-INFINITY, NAN), cpackl(0.0, 0.0),
|
||||
testall(CMPLXL(-INFINITY, NAN), CMPLXL(0.0, 0.0),
|
||||
ALL_STD_EXCEPT, 0, 0);
|
||||
/* cexp(NaN + NaN i) = NaN + NaN i */
|
||||
testall(cpackl(NAN, NAN), cpackl(NAN, NAN),
|
||||
testall(CMPLXL(NAN, NAN), CMPLXL(NAN, NAN),
|
||||
ALL_STD_EXCEPT, 0, 0);
|
||||
}
|
||||
|
||||
@ -229,37 +148,37 @@ test_inf(void)
|
||||
|
||||
/* cexp(x + inf i) = NaN + NaNi and raises invalid */
|
||||
for (i = 0; i < N(finites); i++) {
|
||||
testall(cpackl(finites[i], INFINITY), cpackl(NAN, NAN),
|
||||
testall(CMPLXL(finites[i], INFINITY), CMPLXL(NAN, NAN),
|
||||
ALL_STD_EXCEPT, FE_INVALID, 1);
|
||||
}
|
||||
/* cexp(-inf + yi) = 0 * (cos(y) + sin(y)i) */
|
||||
/* XXX shouldn't raise an inexact exception */
|
||||
testall(cpackl(-INFINITY, M_PI_4), cpackl(0.0, 0.0),
|
||||
testall(CMPLXL(-INFINITY, M_PI_4), CMPLXL(0.0, 0.0),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
testall(cpackl(-INFINITY, 3 * M_PI_4), cpackl(-0.0, 0.0),
|
||||
testall(CMPLXL(-INFINITY, 3 * M_PI_4), CMPLXL(-0.0, 0.0),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
testall(cpackl(-INFINITY, 5 * M_PI_4), cpackl(-0.0, -0.0),
|
||||
testall(CMPLXL(-INFINITY, 5 * M_PI_4), CMPLXL(-0.0, -0.0),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
testall(cpackl(-INFINITY, 7 * M_PI_4), cpackl(0.0, -0.0),
|
||||
testall(CMPLXL(-INFINITY, 7 * M_PI_4), CMPLXL(0.0, -0.0),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
testall(cpackl(-INFINITY, 0.0), cpackl(0.0, 0.0),
|
||||
testall(CMPLXL(-INFINITY, 0.0), CMPLXL(0.0, 0.0),
|
||||
ALL_STD_EXCEPT, 0, 1);
|
||||
testall(cpackl(-INFINITY, -0.0), cpackl(0.0, -0.0),
|
||||
testall(CMPLXL(-INFINITY, -0.0), CMPLXL(0.0, -0.0),
|
||||
ALL_STD_EXCEPT, 0, 1);
|
||||
/* cexp(inf + yi) = inf * (cos(y) + sin(y)i) (except y=0) */
|
||||
/* XXX shouldn't raise an inexact exception */
|
||||
testall(cpackl(INFINITY, M_PI_4), cpackl(INFINITY, INFINITY),
|
||||
testall(CMPLXL(INFINITY, M_PI_4), CMPLXL(INFINITY, INFINITY),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
testall(cpackl(INFINITY, 3 * M_PI_4), cpackl(-INFINITY, INFINITY),
|
||||
testall(CMPLXL(INFINITY, 3 * M_PI_4), CMPLXL(-INFINITY, INFINITY),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
testall(cpackl(INFINITY, 5 * M_PI_4), cpackl(-INFINITY, -INFINITY),
|
||||
testall(CMPLXL(INFINITY, 5 * M_PI_4), CMPLXL(-INFINITY, -INFINITY),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
testall(cpackl(INFINITY, 7 * M_PI_4), cpackl(INFINITY, -INFINITY),
|
||||
testall(CMPLXL(INFINITY, 7 * M_PI_4), CMPLXL(INFINITY, -INFINITY),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
/* cexp(inf + 0i) = inf + 0i */
|
||||
testall(cpackl(INFINITY, 0.0), cpackl(INFINITY, 0.0),
|
||||
testall(CMPLXL(INFINITY, 0.0), CMPLXL(INFINITY, 0.0),
|
||||
ALL_STD_EXCEPT, 0, 1);
|
||||
testall(cpackl(INFINITY, -0.0), cpackl(INFINITY, -0.0),
|
||||
testall(CMPLXL(INFINITY, -0.0), CMPLXL(INFINITY, -0.0),
|
||||
ALL_STD_EXCEPT, 0, 1);
|
||||
}
|
||||
|
||||
@ -270,17 +189,17 @@ test_reals(void)
|
||||
|
||||
for (i = 0; i < N(finites); i++) {
|
||||
/* XXX could check exceptions more meticulously */
|
||||
test(cexp, cpackl(finites[i], 0.0),
|
||||
cpackl(exp(finites[i]), 0.0),
|
||||
test(cexp, CMPLXL(finites[i], 0.0),
|
||||
CMPLXL(exp(finites[i]), 0.0),
|
||||
FE_INVALID | FE_DIVBYZERO, 0, 1);
|
||||
test(cexp, cpackl(finites[i], -0.0),
|
||||
cpackl(exp(finites[i]), -0.0),
|
||||
test(cexp, CMPLXL(finites[i], -0.0),
|
||||
CMPLXL(exp(finites[i]), -0.0),
|
||||
FE_INVALID | FE_DIVBYZERO, 0, 1);
|
||||
test(cexpf, cpackl(finites[i], 0.0),
|
||||
cpackl(expf(finites[i]), 0.0),
|
||||
test(cexpf, CMPLXL(finites[i], 0.0),
|
||||
CMPLXL(expf(finites[i]), 0.0),
|
||||
FE_INVALID | FE_DIVBYZERO, 0, 1);
|
||||
test(cexpf, cpackl(finites[i], -0.0),
|
||||
cpackl(expf(finites[i]), -0.0),
|
||||
test(cexpf, CMPLXL(finites[i], -0.0),
|
||||
CMPLXL(expf(finites[i]), -0.0),
|
||||
FE_INVALID | FE_DIVBYZERO, 0, 1);
|
||||
}
|
||||
}
|
||||
@ -291,17 +210,17 @@ test_imaginaries(void)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N(finites); i++) {
|
||||
test(cexp, cpackl(0.0, finites[i]),
|
||||
cpackl(cos(finites[i]), sin(finites[i])),
|
||||
test(cexp, CMPLXL(0.0, finites[i]),
|
||||
CMPLXL(cos(finites[i]), sin(finites[i])),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
test(cexp, cpackl(-0.0, finites[i]),
|
||||
cpackl(cos(finites[i]), sin(finites[i])),
|
||||
test(cexp, CMPLXL(-0.0, finites[i]),
|
||||
CMPLXL(cos(finites[i]), sin(finites[i])),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
test(cexpf, cpackl(0.0, finites[i]),
|
||||
cpackl(cosf(finites[i]), sinf(finites[i])),
|
||||
test(cexpf, CMPLXL(0.0, finites[i]),
|
||||
CMPLXL(cosf(finites[i]), sinf(finites[i])),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
test(cexpf, cpackl(-0.0, finites[i]),
|
||||
cpackl(cosf(finites[i]), sinf(finites[i])),
|
||||
test(cexpf, CMPLXL(-0.0, finites[i]),
|
||||
CMPLXL(cosf(finites[i]), sinf(finites[i])),
|
||||
ALL_STD_EXCEPT & ~FE_INEXACT, 0, 1);
|
||||
}
|
||||
}
|
||||
@ -326,12 +245,12 @@ test_small(void)
|
||||
b = tests[i + 1];
|
||||
x = tests[i + 2];
|
||||
y = tests[i + 3];
|
||||
test_tol(cexp, cpackl(a, b), cpackl(x, y), 3 * DBL_ULP());
|
||||
test_tol(cexp, CMPLXL(a, b), CMPLXL(x, y), 3 * DBL_ULP());
|
||||
|
||||
/* float doesn't have enough precision to pass these tests */
|
||||
if (x == 0 || y == 0)
|
||||
continue;
|
||||
test_tol(cexpf, cpackl(a, b), cpackl(x, y), 1 * FLT_ULP());
|
||||
test_tol(cexpf, CMPLXL(a, b), CMPLXL(x, y), 1 * FLT_ULP());
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,27 +259,27 @@ void
|
||||
test_large(void)
|
||||
{
|
||||
|
||||
test_tol(cexp, cpackl(709.79, 0x1p-1074),
|
||||
cpackl(INFINITY, 8.94674309915433533273e-16), DBL_ULP());
|
||||
test_tol(cexp, cpackl(1000, 0x1p-1074),
|
||||
cpackl(INFINITY, 9.73344457300016401328e+110), DBL_ULP());
|
||||
test_tol(cexp, cpackl(1400, 0x1p-1074),
|
||||
cpackl(INFINITY, 5.08228858149196559681e+284), DBL_ULP());
|
||||
test_tol(cexp, cpackl(900, 0x1.23456789abcdep-1020),
|
||||
cpackl(INFINITY, 7.42156649354218408074e+83), DBL_ULP());
|
||||
test_tol(cexp, cpackl(1300, 0x1.23456789abcdep-1020),
|
||||
cpackl(INFINITY, 3.87514844965996756704e+257), DBL_ULP());
|
||||
test_tol(cexp, CMPLXL(709.79, 0x1p-1074),
|
||||
CMPLXL(INFINITY, 8.94674309915433533273e-16), DBL_ULP());
|
||||
test_tol(cexp, CMPLXL(1000, 0x1p-1074),
|
||||
CMPLXL(INFINITY, 9.73344457300016401328e+110), DBL_ULP());
|
||||
test_tol(cexp, CMPLXL(1400, 0x1p-1074),
|
||||
CMPLXL(INFINITY, 5.08228858149196559681e+284), DBL_ULP());
|
||||
test_tol(cexp, CMPLXL(900, 0x1.23456789abcdep-1020),
|
||||
CMPLXL(INFINITY, 7.42156649354218408074e+83), DBL_ULP());
|
||||
test_tol(cexp, CMPLXL(1300, 0x1.23456789abcdep-1020),
|
||||
CMPLXL(INFINITY, 3.87514844965996756704e+257), DBL_ULP());
|
||||
|
||||
test_tol(cexpf, cpackl(88.73, 0x1p-149),
|
||||
cpackl(INFINITY, 4.80265603e-07), 2 * FLT_ULP());
|
||||
test_tol(cexpf, cpackl(90, 0x1p-149),
|
||||
cpackl(INFINITY, 1.7101492622e-06f), 2 * FLT_ULP());
|
||||
test_tol(cexpf, cpackl(192, 0x1p-149),
|
||||
cpackl(INFINITY, 3.396809344e+38f), 2 * FLT_ULP());
|
||||
test_tol(cexpf, cpackl(120, 0x1.234568p-120),
|
||||
cpackl(INFINITY, 1.1163382522e+16f), 2 * FLT_ULP());
|
||||
test_tol(cexpf, cpackl(170, 0x1.234568p-120),
|
||||
cpackl(INFINITY, 5.7878851079e+37f), 2 * FLT_ULP());
|
||||
test_tol(cexpf, CMPLXL(88.73, 0x1p-149),
|
||||
CMPLXL(INFINITY, 4.80265603e-07), 2 * FLT_ULP());
|
||||
test_tol(cexpf, CMPLXL(90, 0x1p-149),
|
||||
CMPLXL(INFINITY, 1.7101492622e-06f), 2 * FLT_ULP());
|
||||
test_tol(cexpf, CMPLXL(192, 0x1p-149),
|
||||
CMPLXL(INFINITY, 3.396809344e+38f), 2 * FLT_ULP());
|
||||
test_tol(cexpf, CMPLXL(120, 0x1.234568p-120),
|
||||
CMPLXL(INFINITY, 1.1163382522e+16f), 2 * FLT_ULP());
|
||||
test_tol(cexpf, CMPLXL(170, 0x1.234568p-120),
|
||||
CMPLXL(INFINITY, 5.7878851079e+37f), 2 * FLT_ULP());
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "test-utils.h"
|
||||
|
||||
#pragma STDC CX_LIMITED_RANGE off
|
||||
|
||||
/* Make sure gcc doesn't use builtin versions of these or honor __pure2. */
|
||||
@ -50,27 +52,6 @@ static float (*libcimagf)(float complex) = cimagf;
|
||||
static double (*libcimag)(double complex) = cimag;
|
||||
static long double (*libcimagl)(long double complex) = cimagl;
|
||||
|
||||
/*
|
||||
* Compare d1 and d2 using special rules: NaN == NaN and +0 != -0.
|
||||
* Fail an assertion if they differ.
|
||||
*/
|
||||
static int
|
||||
fpequal(long double d1, long double d2)
|
||||
{
|
||||
|
||||
if (d1 != d2)
|
||||
return (isnan(d1) && isnan(d2));
|
||||
return (copysignl(1.0, d1) == copysignl(1.0, d2));
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal(long double complex d1, long double complex d2)
|
||||
{
|
||||
|
||||
return (fpequal(creall(d1), creall(d2)) &&
|
||||
fpequal(cimagl(d1), cimagl(d2)));
|
||||
}
|
||||
|
||||
static const double tests[] = {
|
||||
/* a + bI */
|
||||
0.0, 0.0,
|
||||
|
@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "test-utils.h"
|
||||
|
||||
#define N(i) (sizeof(i) / sizeof((i)[0]))
|
||||
|
||||
/*
|
||||
@ -62,23 +64,6 @@ _csqrt(long double complex d)
|
||||
|
||||
#pragma STDC CX_LIMITED_RANGE off
|
||||
|
||||
/*
|
||||
* XXX gcc implements complex multiplication incorrectly. In
|
||||
* particular, it implements it as if the CX_LIMITED_RANGE pragma
|
||||
* were ON. Consequently, we need this function to form numbers
|
||||
* such as x + INFINITY * I, since gcc evalutes INFINITY * I as
|
||||
* NaN + INFINITY * I.
|
||||
*/
|
||||
static inline long double complex
|
||||
cpackl(long double x, long double y)
|
||||
{
|
||||
long double complex z;
|
||||
|
||||
__real__ z = x;
|
||||
__imag__ z = y;
|
||||
return (z);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare d1 and d2 using special rules: NaN == NaN and +0 != -0.
|
||||
* Fail an assertion if they differ.
|
||||
@ -87,20 +72,7 @@ static void
|
||||
assert_equal(long double complex d1, long double complex d2)
|
||||
{
|
||||
|
||||
if (isnan(creall(d1))) {
|
||||
assert(isnan(creall(d2)));
|
||||
} else {
|
||||
assert(creall(d1) == creall(d2));
|
||||
assert(copysignl(1.0, creall(d1)) ==
|
||||
copysignl(1.0, creall(d2)));
|
||||
}
|
||||
if (isnan(cimagl(d1))) {
|
||||
assert(isnan(cimagl(d2)));
|
||||
} else {
|
||||
assert(cimagl(d1) == cimagl(d2));
|
||||
assert(copysignl(1.0, cimagl(d1)) ==
|
||||
copysignl(1.0, cimagl(d2)));
|
||||
}
|
||||
assert(cfpequal(d1, d2));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -161,7 +133,7 @@ test_finite()
|
||||
b = tests[i + 1] * mults[j] * mults[j];
|
||||
x = tests[i + 2] * mults[j];
|
||||
y = tests[i + 3] * mults[j];
|
||||
assert(t_csqrt(cpackl(a, b)) == cpackl(x, y));
|
||||
assert(t_csqrt(CMPLXL(a, b)) == CMPLXL(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,10 +146,10 @@ static void
|
||||
test_zeros()
|
||||
{
|
||||
|
||||
assert_equal(t_csqrt(cpackl(0.0, 0.0)), cpackl(0.0, 0.0));
|
||||
assert_equal(t_csqrt(cpackl(-0.0, 0.0)), cpackl(0.0, 0.0));
|
||||
assert_equal(t_csqrt(cpackl(0.0, -0.0)), cpackl(0.0, -0.0));
|
||||
assert_equal(t_csqrt(cpackl(-0.0, -0.0)), cpackl(0.0, -0.0));
|
||||
assert_equal(t_csqrt(CMPLXL(0.0, 0.0)), CMPLXL(0.0, 0.0));
|
||||
assert_equal(t_csqrt(CMPLXL(-0.0, 0.0)), CMPLXL(0.0, 0.0));
|
||||
assert_equal(t_csqrt(CMPLXL(0.0, -0.0)), CMPLXL(0.0, -0.0));
|
||||
assert_equal(t_csqrt(CMPLXL(-0.0, -0.0)), CMPLXL(0.0, -0.0));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -199,15 +171,15 @@ test_infinities()
|
||||
|
||||
for (i = 0; i < N(vals); i++) {
|
||||
if (isfinite(vals[i])) {
|
||||
assert_equal(t_csqrt(cpackl(-INFINITY, vals[i])),
|
||||
cpackl(0.0, copysignl(INFINITY, vals[i])));
|
||||
assert_equal(t_csqrt(cpackl(INFINITY, vals[i])),
|
||||
cpackl(INFINITY, copysignl(0.0, vals[i])));
|
||||
assert_equal(t_csqrt(CMPLXL(-INFINITY, vals[i])),
|
||||
CMPLXL(0.0, copysignl(INFINITY, vals[i])));
|
||||
assert_equal(t_csqrt(CMPLXL(INFINITY, vals[i])),
|
||||
CMPLXL(INFINITY, copysignl(0.0, vals[i])));
|
||||
}
|
||||
assert_equal(t_csqrt(cpackl(vals[i], INFINITY)),
|
||||
cpackl(INFINITY, INFINITY));
|
||||
assert_equal(t_csqrt(cpackl(vals[i], -INFINITY)),
|
||||
cpackl(INFINITY, -INFINITY));
|
||||
assert_equal(t_csqrt(CMPLXL(vals[i], INFINITY)),
|
||||
CMPLXL(INFINITY, INFINITY));
|
||||
assert_equal(t_csqrt(CMPLXL(vals[i], -INFINITY)),
|
||||
CMPLXL(INFINITY, -INFINITY));
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,26 +190,26 @@ static void
|
||||
test_nans()
|
||||
{
|
||||
|
||||
assert(creall(t_csqrt(cpackl(INFINITY, NAN))) == INFINITY);
|
||||
assert(isnan(cimagl(t_csqrt(cpackl(INFINITY, NAN)))));
|
||||
assert(creall(t_csqrt(CMPLXL(INFINITY, NAN))) == INFINITY);
|
||||
assert(isnan(cimagl(t_csqrt(CMPLXL(INFINITY, NAN)))));
|
||||
|
||||
assert(isnan(creall(t_csqrt(cpackl(-INFINITY, NAN)))));
|
||||
assert(isinf(cimagl(t_csqrt(cpackl(-INFINITY, NAN)))));
|
||||
assert(isnan(creall(t_csqrt(CMPLXL(-INFINITY, NAN)))));
|
||||
assert(isinf(cimagl(t_csqrt(CMPLXL(-INFINITY, NAN)))));
|
||||
|
||||
assert_equal(t_csqrt(cpackl(NAN, INFINITY)),
|
||||
cpackl(INFINITY, INFINITY));
|
||||
assert_equal(t_csqrt(cpackl(NAN, -INFINITY)),
|
||||
cpackl(INFINITY, -INFINITY));
|
||||
assert_equal(t_csqrt(CMPLXL(NAN, INFINITY)),
|
||||
CMPLXL(INFINITY, INFINITY));
|
||||
assert_equal(t_csqrt(CMPLXL(NAN, -INFINITY)),
|
||||
CMPLXL(INFINITY, -INFINITY));
|
||||
|
||||
assert_equal(t_csqrt(cpackl(0.0, NAN)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(-0.0, NAN)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(42.0, NAN)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(-42.0, NAN)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(NAN, 0.0)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(NAN, -0.0)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(NAN, 42.0)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(NAN, -42.0)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(cpackl(NAN, NAN)), cpackl(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(0.0, NAN)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(-0.0, NAN)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(42.0, NAN)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(-42.0, NAN)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(NAN, 0.0)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(NAN, -0.0)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(NAN, 42.0)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(NAN, -42.0)), CMPLXL(NAN, NAN));
|
||||
assert_equal(t_csqrt(CMPLXL(NAN, NAN)), CMPLXL(NAN, NAN));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -254,7 +226,7 @@ test_overflow(int maxexp)
|
||||
|
||||
a = ldexpl(115 * 0x1p-8, maxexp);
|
||||
b = ldexpl(252 * 0x1p-8, maxexp);
|
||||
result = t_csqrt(cpackl(a, b));
|
||||
result = t_csqrt(CMPLXL(a, b));
|
||||
assert(creall(result) == ldexpl(14 * 0x1p-4, maxexp / 2));
|
||||
assert(cimagl(result) == ldexpl(9 * 0x1p-4, maxexp / 2));
|
||||
}
|
||||
|
@ -38,45 +38,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#define OPT_INVALID (ALL_STD_EXCEPT & ~FE_INVALID)
|
||||
#define OPT_INEXACT (ALL_STD_EXCEPT & ~FE_INEXACT)
|
||||
#define FLT_ULP() ldexpl(1.0, 1 - FLT_MANT_DIG)
|
||||
#define DBL_ULP() ldexpl(1.0, 1 - DBL_MANT_DIG)
|
||||
#define LDBL_ULP() ldexpl(1.0, 1 - LDBL_MANT_DIG)
|
||||
#include "test-utils.h"
|
||||
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#pragma STDC CX_LIMITED_RANGE OFF
|
||||
|
||||
/*
|
||||
* XXX gcc implements complex multiplication incorrectly. In
|
||||
* particular, it implements it as if the CX_LIMITED_RANGE pragma
|
||||
* were ON. Consequently, we need this function to form numbers
|
||||
* such as x + INFINITY * I, since gcc evalutes INFINITY * I as
|
||||
* NaN + INFINITY * I.
|
||||
*/
|
||||
static inline long double complex
|
||||
cpackl(long double x, long double y)
|
||||
{
|
||||
long double complex z;
|
||||
|
||||
__real__ z = x;
|
||||
__imag__ z = y;
|
||||
return (z);
|
||||
}
|
||||
|
||||
/* Flags that determine whether to check the signs of the result. */
|
||||
#define CS_REAL 1
|
||||
#define CS_IMAG 2
|
||||
#define CS_BOTH (CS_REAL | CS_IMAG)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define debug(...) (void)0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Test that a function returns the correct value and sets the
|
||||
* exception flags correctly. The exceptmask specifies which
|
||||
@ -95,8 +61,8 @@ cpackl(long double x, long double y)
|
||||
debug(" testing %s(%Lg + %Lg I) == %Lg + %Lg I\n", #func, \
|
||||
creall(_d), cimagl(_d), creall(result), cimagl(result)); \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(cfpequal((func)(_d), (result), (checksign))); \
|
||||
assert(((func), fetestexcept(exceptmask) == (excepts))); \
|
||||
assert(cfpequal_cs((func)(_d), (result), (checksign))); \
|
||||
assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
@ -108,7 +74,7 @@ cpackl(long double x, long double y)
|
||||
volatile long double complex _d = z; \
|
||||
debug(" testing %s(%Lg + %Lg I) ~= %Lg + %Lg I\n", #func, \
|
||||
creall(_d), cimagl(_d), creall(result), cimagl(result)); \
|
||||
assert(cfpequal_tol((func)(_d), (result), (tol))); \
|
||||
assert(cfpequal_tol((func)(_d), (result), (tol), FPE_ABS_ZERO)); \
|
||||
} while (0)
|
||||
|
||||
/* These wrappers apply the identities f(conj(z)) = conj(f(z)). */
|
||||
@ -152,79 +118,18 @@ cpackl(long double x, long double y)
|
||||
test_tol(func, -x, result, tol * DBL_ULP()); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
* If checksign is 0, we compare the absolute values instead.
|
||||
*/
|
||||
static int
|
||||
fpequal(long double x, long double y, int checksign)
|
||||
{
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (checksign)
|
||||
return (x == y && !signbit(x) == !signbit(y));
|
||||
else
|
||||
return (fabsl(x) == fabsl(y));
|
||||
}
|
||||
|
||||
static int
|
||||
fpequal_tol(long double x, long double y, long double tol)
|
||||
{
|
||||
fenv_t env;
|
||||
int ret;
|
||||
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (!signbit(x) != !signbit(y) && tol == 0)
|
||||
return (0);
|
||||
if (x == y)
|
||||
return (1);
|
||||
if (tol == 0)
|
||||
return (0);
|
||||
|
||||
/* Hard case: need to check the tolerance. */
|
||||
feholdexcept(&env);
|
||||
/*
|
||||
* For our purposes here, if y=0, we interpret tol as an absolute
|
||||
* tolerance. This is to account for roundoff in the input, e.g.,
|
||||
* cos(Pi/2) ~= 0.
|
||||
*/
|
||||
if (y == 0.0)
|
||||
ret = fabsl(x - y) <= fabsl(tol);
|
||||
else
|
||||
ret = fabsl(x - y) <= fabsl(y * tol);
|
||||
fesetenv(&env);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal(long double complex x, long double complex y, int checksign)
|
||||
{
|
||||
return (fpequal(creal(x), creal(y), checksign & CS_REAL)
|
||||
&& fpequal(cimag(x), cimag(y), checksign & CS_IMAG));
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal_tol(long double complex x, long double complex y, long double tol)
|
||||
{
|
||||
return (fpequal_tol(creal(x), creal(y), tol)
|
||||
&& fpequal_tol(cimag(x), cimag(y), tol));
|
||||
}
|
||||
|
||||
|
||||
/* Tests for 0 */
|
||||
void
|
||||
test_zero(void)
|
||||
{
|
||||
long double complex zero = cpackl(0.0, 0.0);
|
||||
long double complex zero = CMPLXL(0.0, 0.0);
|
||||
|
||||
/* csinh(0) = ctanh(0) = 0; ccosh(0) = 1 (no exceptions raised) */
|
||||
testall_odd(csinh, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
|
||||
testall_odd(csin, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
|
||||
testall_even(ccosh, zero, 1.0, ALL_STD_EXCEPT, 0, CS_BOTH);
|
||||
testall_even(ccos, zero, cpackl(1.0, -0.0), ALL_STD_EXCEPT, 0, CS_BOTH);
|
||||
testall_even(ccos, zero, CMPLXL(1.0, -0.0), ALL_STD_EXCEPT, 0, CS_BOTH);
|
||||
testall_odd(ctanh, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
|
||||
testall_odd(ctan, zero, zero, ALL_STD_EXCEPT, 0, CS_BOTH);
|
||||
}
|
||||
@ -235,7 +140,7 @@ test_zero(void)
|
||||
void
|
||||
test_nan()
|
||||
{
|
||||
long double complex nan_nan = cpackl(NAN, NAN);
|
||||
long double complex nan_nan = CMPLXL(NAN, NAN);
|
||||
long double complex z;
|
||||
|
||||
/*
|
||||
@ -256,7 +161,7 @@ test_nan()
|
||||
testall_even(ccos, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
|
||||
testall_odd(ctan, z, nan_nan, ALL_STD_EXCEPT, 0, 0);
|
||||
|
||||
z = cpackl(42, NAN);
|
||||
z = CMPLXL(42, NAN);
|
||||
testall_odd(csinh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_even(ccosh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
/* XXX We allow a spurious inexact exception here. */
|
||||
@ -265,7 +170,7 @@ test_nan()
|
||||
testall_even(ccos, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_odd(ctan, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
|
||||
z = cpackl(NAN, 42);
|
||||
z = CMPLXL(NAN, 42);
|
||||
testall_odd(csinh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_even(ccosh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_odd(ctanh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
@ -274,38 +179,38 @@ test_nan()
|
||||
/* XXX We allow a spurious inexact exception here. */
|
||||
testall_odd(ctan, z, nan_nan, OPT_INVALID & ~FE_INEXACT, 0, 0);
|
||||
|
||||
z = cpackl(NAN, INFINITY);
|
||||
z = CMPLXL(NAN, INFINITY);
|
||||
testall_odd(csinh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_even(ccosh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_odd(ctanh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_odd(csin, z, cpackl(NAN, INFINITY), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccos, z, cpackl(INFINITY, NAN), ALL_STD_EXCEPT, 0,
|
||||
testall_odd(csin, z, CMPLXL(NAN, INFINITY), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccos, z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0,
|
||||
CS_IMAG);
|
||||
testall_odd(ctan, z, cpackl(0, 1), ALL_STD_EXCEPT, 0, CS_IMAG);
|
||||
testall_odd(ctan, z, CMPLXL(0, 1), ALL_STD_EXCEPT, 0, CS_IMAG);
|
||||
|
||||
z = cpackl(INFINITY, NAN);
|
||||
testall_odd(csinh, z, cpackl(INFINITY, NAN), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccosh, z, cpackl(INFINITY, NAN), ALL_STD_EXCEPT, 0,
|
||||
z = CMPLXL(INFINITY, NAN);
|
||||
testall_odd(csinh, z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccosh, z, CMPLXL(INFINITY, NAN), ALL_STD_EXCEPT, 0,
|
||||
CS_REAL);
|
||||
testall_odd(ctanh, z, cpackl(1, 0), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_odd(ctanh, z, CMPLXL(1, 0), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_odd(csin, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_even(ccos, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_odd(ctan, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
|
||||
z = cpackl(0, NAN);
|
||||
testall_odd(csinh, z, cpackl(0, NAN), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccosh, z, cpackl(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
z = CMPLXL(0, NAN);
|
||||
testall_odd(csinh, z, CMPLXL(0, NAN), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccosh, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_odd(ctanh, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
testall_odd(csin, z, cpackl(0, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_even(ccos, z, cpackl(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_odd(ctan, z, cpackl(0, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_odd(csin, z, CMPLXL(0, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_even(ccos, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_odd(ctan, z, CMPLXL(0, NAN), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
|
||||
z = cpackl(NAN, 0);
|
||||
testall_odd(csinh, z, cpackl(NAN, 0), ALL_STD_EXCEPT, 0, CS_IMAG);
|
||||
testall_even(ccosh, z, cpackl(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_odd(ctanh, z, cpackl(NAN, 0), ALL_STD_EXCEPT, 0, CS_IMAG);
|
||||
testall_odd(csin, z, cpackl(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccos, z, cpackl(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
z = CMPLXL(NAN, 0);
|
||||
testall_odd(csinh, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, CS_IMAG);
|
||||
testall_even(ccosh, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_odd(ctanh, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, CS_IMAG);
|
||||
testall_odd(csin, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_even(ccos, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, 0, 0);
|
||||
testall_odd(ctan, z, nan_nan, OPT_INVALID, 0, 0);
|
||||
}
|
||||
|
||||
@ -325,53 +230,53 @@ test_inf(void)
|
||||
* 0,Inf +-0,NaN inval NaN,+-0 inval NaN,NaN inval
|
||||
* finite,Inf NaN,NaN inval NaN,NaN inval NaN,NaN inval
|
||||
*/
|
||||
z = cpackl(INFINITY, INFINITY);
|
||||
testall_odd(csinh, z, cpackl(INFINITY, NAN),
|
||||
z = CMPLXL(INFINITY, INFINITY);
|
||||
testall_odd(csinh, z, CMPLXL(INFINITY, NAN),
|
||||
ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccosh, z, cpackl(INFINITY, NAN),
|
||||
testall_even(ccosh, z, CMPLXL(INFINITY, NAN),
|
||||
ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_odd(ctanh, z, cpackl(1, 0), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_odd(csin, z, cpackl(NAN, INFINITY),
|
||||
testall_odd(ctanh, z, CMPLXL(1, 0), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_odd(csin, z, CMPLXL(NAN, INFINITY),
|
||||
ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccos, z, cpackl(INFINITY, NAN),
|
||||
testall_even(ccos, z, CMPLXL(INFINITY, NAN),
|
||||
ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_odd(ctan, z, cpackl(0, 1), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
testall_odd(ctan, z, CMPLXL(0, 1), ALL_STD_EXCEPT, 0, CS_REAL);
|
||||
|
||||
/* XXX We allow spurious inexact exceptions here (hard to avoid). */
|
||||
for (i = 0; i < sizeof(finites) / sizeof(finites[0]); i++) {
|
||||
z = cpackl(INFINITY, finites[i]);
|
||||
z = CMPLXL(INFINITY, finites[i]);
|
||||
c = INFINITY * cosl(finites[i]);
|
||||
s = finites[i] == 0 ? finites[i] : INFINITY * sinl(finites[i]);
|
||||
testall_odd(csinh, z, cpackl(c, s), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_even(ccosh, z, cpackl(c, s), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_odd(ctanh, z, cpackl(1, 0 * sin(finites[i] * 2)),
|
||||
testall_odd(csinh, z, CMPLXL(c, s), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_even(ccosh, z, CMPLXL(c, s), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_odd(ctanh, z, CMPLXL(1, 0 * sin(finites[i] * 2)),
|
||||
OPT_INEXACT, 0, CS_BOTH);
|
||||
z = cpackl(finites[i], INFINITY);
|
||||
testall_odd(csin, z, cpackl(s, c), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_even(ccos, z, cpackl(c, -s), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_odd(ctan, z, cpackl(0 * sin(finites[i] * 2), 1),
|
||||
z = CMPLXL(finites[i], INFINITY);
|
||||
testall_odd(csin, z, CMPLXL(s, c), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_even(ccos, z, CMPLXL(c, -s), OPT_INEXACT, 0, CS_BOTH);
|
||||
testall_odd(ctan, z, CMPLXL(0 * sin(finites[i] * 2), 1),
|
||||
OPT_INEXACT, 0, CS_BOTH);
|
||||
}
|
||||
|
||||
z = cpackl(0, INFINITY);
|
||||
testall_odd(csinh, z, cpackl(0, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccosh, z, cpackl(NAN, 0), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_odd(ctanh, z, cpackl(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
z = cpackl(INFINITY, 0);
|
||||
testall_odd(csin, z, cpackl(NAN, 0), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccos, z, cpackl(NAN, 0), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_odd(ctan, z, cpackl(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
z = CMPLXL(0, INFINITY);
|
||||
testall_odd(csinh, z, CMPLXL(0, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccosh, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_odd(ctanh, z, CMPLXL(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
z = CMPLXL(INFINITY, 0);
|
||||
testall_odd(csin, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccos, z, CMPLXL(NAN, 0), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_odd(ctan, z, CMPLXL(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
|
||||
z = cpackl(42, INFINITY);
|
||||
testall_odd(csinh, z, cpackl(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccosh, z, cpackl(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
z = CMPLXL(42, INFINITY);
|
||||
testall_odd(csinh, z, CMPLXL(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccosh, z, CMPLXL(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
/* XXX We allow a spurious inexact exception here. */
|
||||
testall_odd(ctanh, z, cpackl(NAN, NAN), OPT_INEXACT, FE_INVALID, 0);
|
||||
z = cpackl(INFINITY, 42);
|
||||
testall_odd(csin, z, cpackl(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccos, z, cpackl(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_odd(ctanh, z, CMPLXL(NAN, NAN), OPT_INEXACT, FE_INVALID, 0);
|
||||
z = CMPLXL(INFINITY, 42);
|
||||
testall_odd(csin, z, CMPLXL(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
testall_even(ccos, z, CMPLXL(NAN, NAN), ALL_STD_EXCEPT, FE_INVALID, 0);
|
||||
/* XXX We allow a spurious inexact exception here. */
|
||||
testall_odd(ctan, z, cpackl(NAN, NAN), OPT_INEXACT, FE_INVALID, 0);
|
||||
testall_odd(ctan, z, CMPLXL(NAN, NAN), OPT_INEXACT, FE_INVALID, 0);
|
||||
}
|
||||
|
||||
/* Tests along the real and imaginary axes. */
|
||||
@ -387,26 +292,26 @@ test_axes(void)
|
||||
|
||||
for (i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
|
||||
/* Real axis */
|
||||
z = cpackl(nums[i], 0.0);
|
||||
testall_odd_tol(csinh, z, cpackl(sinh(nums[i]), 0), 0);
|
||||
testall_even_tol(ccosh, z, cpackl(cosh(nums[i]), 0), 0);
|
||||
testall_odd_tol(ctanh, z, cpackl(tanh(nums[i]), 0), 1);
|
||||
testall_odd_tol(csin, z, cpackl(sin(nums[i]),
|
||||
z = CMPLXL(nums[i], 0.0);
|
||||
testall_odd_tol(csinh, z, CMPLXL(sinh(nums[i]), 0), 0);
|
||||
testall_even_tol(ccosh, z, CMPLXL(cosh(nums[i]), 0), 0);
|
||||
testall_odd_tol(ctanh, z, CMPLXL(tanh(nums[i]), 0), 1);
|
||||
testall_odd_tol(csin, z, CMPLXL(sin(nums[i]),
|
||||
copysign(0, cos(nums[i]))), 0);
|
||||
testall_even_tol(ccos, z, cpackl(cos(nums[i]),
|
||||
testall_even_tol(ccos, z, CMPLXL(cos(nums[i]),
|
||||
-copysign(0, sin(nums[i]))), 0);
|
||||
testall_odd_tol(ctan, z, cpackl(tan(nums[i]), 0), 1);
|
||||
testall_odd_tol(ctan, z, CMPLXL(tan(nums[i]), 0), 1);
|
||||
|
||||
/* Imaginary axis */
|
||||
z = cpackl(0.0, nums[i]);
|
||||
testall_odd_tol(csinh, z, cpackl(copysign(0, cos(nums[i])),
|
||||
z = CMPLXL(0.0, nums[i]);
|
||||
testall_odd_tol(csinh, z, CMPLXL(copysign(0, cos(nums[i])),
|
||||
sin(nums[i])), 0);
|
||||
testall_even_tol(ccosh, z, cpackl(cos(nums[i]),
|
||||
testall_even_tol(ccosh, z, CMPLXL(cos(nums[i]),
|
||||
copysign(0, sin(nums[i]))), 0);
|
||||
testall_odd_tol(ctanh, z, cpackl(0, tan(nums[i])), 1);
|
||||
testall_odd_tol(csin, z, cpackl(0, sinh(nums[i])), 0);
|
||||
testall_even_tol(ccos, z, cpackl(cosh(nums[i]), -0.0), 0);
|
||||
testall_odd_tol(ctan, z, cpackl(0, tanh(nums[i])), 1);
|
||||
testall_odd_tol(ctanh, z, CMPLXL(0, tan(nums[i])), 1);
|
||||
testall_odd_tol(csin, z, CMPLXL(0, sinh(nums[i])), 0);
|
||||
testall_even_tol(ccos, z, CMPLXL(cosh(nums[i]), -0.0), 0);
|
||||
testall_odd_tol(ctan, z, CMPLXL(0, tanh(nums[i])), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,13 +367,13 @@ test_small(void)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||
z = cpackl(tests[i].a, tests[i].b);
|
||||
z = CMPLXL(tests[i].a, tests[i].b);
|
||||
testall_odd_tol(csinh, z,
|
||||
cpackl(tests[i].sinh_a, tests[i].sinh_b), 1.1);
|
||||
CMPLXL(tests[i].sinh_a, tests[i].sinh_b), 1.1);
|
||||
testall_even_tol(ccosh, z,
|
||||
cpackl(tests[i].cosh_a, tests[i].cosh_b), 1.1);
|
||||
CMPLXL(tests[i].cosh_a, tests[i].cosh_b), 1.1);
|
||||
testall_odd_tol(ctanh, z,
|
||||
cpackl(tests[i].tanh_a, tests[i].tanh_b), 1.1);
|
||||
CMPLXL(tests[i].tanh_a, tests[i].tanh_b), 1.1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,36 +384,36 @@ test_large(void)
|
||||
long double complex z;
|
||||
|
||||
/* tanh() uses a threshold around x=22, so check both sides. */
|
||||
z = cpackl(21, 0.78539816339744830961566084581987572L);
|
||||
z = CMPLXL(21, 0.78539816339744830961566084581987572L);
|
||||
testall_odd_tol(ctanh, z,
|
||||
cpackl(1.0, 1.14990445285871196133287617611468468e-18L), 1);
|
||||
CMPLXL(1.0, 1.14990445285871196133287617611468468e-18L), 1);
|
||||
z++;
|
||||
testall_odd_tol(ctanh, z,
|
||||
cpackl(1.0, 1.55622644822675930314266334585597964e-19L), 1);
|
||||
CMPLXL(1.0, 1.55622644822675930314266334585597964e-19L), 1);
|
||||
|
||||
z = cpackl(355, 0.78539816339744830961566084581987572L);
|
||||
z = CMPLXL(355, 0.78539816339744830961566084581987572L);
|
||||
testall_odd_tol(ctanh, z,
|
||||
cpackl(1.0, 8.95257245135025991216632140458264468e-309L), 1);
|
||||
z = cpackl(30, 0x1p1023L);
|
||||
CMPLXL(1.0, 8.95257245135025991216632140458264468e-309L), 1);
|
||||
z = CMPLXL(30, 0x1p1023L);
|
||||
testall_odd_tol(ctanh, z,
|
||||
cpackl(1.0, -1.62994325413993477997492170229268382e-26L), 1);
|
||||
z = cpackl(1, 0x1p1023L);
|
||||
CMPLXL(1.0, -1.62994325413993477997492170229268382e-26L), 1);
|
||||
z = CMPLXL(1, 0x1p1023L);
|
||||
testall_odd_tol(ctanh, z,
|
||||
cpackl(0.878606311888306869546254022621986509L,
|
||||
CMPLXL(0.878606311888306869546254022621986509L,
|
||||
-0.225462792499754505792678258169527424L), 1);
|
||||
|
||||
z = cpackl(710.6, 0.78539816339744830961566084581987572L);
|
||||
z = CMPLXL(710.6, 0.78539816339744830961566084581987572L);
|
||||
testall_odd_tol(csinh, z,
|
||||
cpackl(1.43917579766621073533185387499658944e308L,
|
||||
CMPLXL(1.43917579766621073533185387499658944e308L,
|
||||
1.43917579766621073533185387499658944e308L), 1);
|
||||
testall_even_tol(ccosh, z,
|
||||
cpackl(1.43917579766621073533185387499658944e308L,
|
||||
CMPLXL(1.43917579766621073533185387499658944e308L,
|
||||
1.43917579766621073533185387499658944e308L), 1);
|
||||
|
||||
z = cpackl(1500, 0.78539816339744830961566084581987572L);
|
||||
testall_odd(csinh, z, cpackl(INFINITY, INFINITY), OPT_INEXACT,
|
||||
z = CMPLXL(1500, 0.78539816339744830961566084581987572L);
|
||||
testall_odd(csinh, z, CMPLXL(INFINITY, INFINITY), OPT_INEXACT,
|
||||
FE_OVERFLOW, CS_BOTH);
|
||||
testall_even(ccosh, z, cpackl(INFINITY, INFINITY), OPT_INEXACT,
|
||||
testall_even(ccosh, z, CMPLXL(INFINITY, INFINITY), OPT_INEXACT,
|
||||
FE_OVERFLOW, CS_BOTH);
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
|
||||
@ -63,7 +62,7 @@ __FBSDID("$FreeBSD$");
|
||||
volatile long double _d = x; \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(fpequal((func)(_d), (result))); \
|
||||
assert(((func), fetestexcept(exceptmask) == (excepts))); \
|
||||
assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
|
||||
} while (0)
|
||||
|
||||
/* Test all the functions that compute b^x. */
|
||||
@ -81,17 +80,6 @@ __FBSDID("$FreeBSD$");
|
||||
test(expm1f, x, result, exceptmask, excepts); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
*/
|
||||
int
|
||||
fpequal(long double x, long double y)
|
||||
{
|
||||
return ((x == y && !signbit(x) == !signbit(y)) || isnan(x) && isnan(y));
|
||||
}
|
||||
|
||||
void
|
||||
run_generic_tests(void)
|
||||
{
|
||||
|
@ -37,8 +37,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
|
||||
@ -53,14 +52,17 @@ __FBSDID("$FreeBSD$");
|
||||
* meaningful error messages.
|
||||
*/
|
||||
#define test(func, x, y, z, result, exceptmask, excepts) do { \
|
||||
volatile long double _vx = (x), _vy = (y), _vz = (z); \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(fpequal((func)((x), (y), (z)), (result))); \
|
||||
assert(((func), fetestexcept(exceptmask) == (excepts))); \
|
||||
assert(fpequal((func)(_vx, _vy, _vz), (result))); \
|
||||
assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
|
||||
} while (0)
|
||||
|
||||
#define testall(x, y, z, result, exceptmask, excepts) do { \
|
||||
test(fma, (x), (y), (z), (double)(result), (exceptmask), (excepts)); \
|
||||
test(fmaf, (x), (y), (z), (float)(result), (exceptmask), (excepts)); \
|
||||
test(fma, (double)(x), (double)(y), (double)(z), \
|
||||
(double)(result), (exceptmask), (excepts)); \
|
||||
test(fmaf, (float)(x), (float)(y), (float)(z), \
|
||||
(float)(result), (exceptmask), (excepts)); \
|
||||
test(fmal, (x), (y), (z), (result), (exceptmask), (excepts)); \
|
||||
} while (0)
|
||||
|
||||
@ -82,19 +84,6 @@ __FBSDID("$FreeBSD$");
|
||||
*/
|
||||
volatile double one = 1.0;
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
*/
|
||||
int
|
||||
fpequal(long double x, long double y)
|
||||
{
|
||||
|
||||
return ((x == y && !signbit(x) == !signbit(y))
|
||||
|| (isnan(x) && isnan(y)));
|
||||
}
|
||||
|
||||
static void
|
||||
test_zeroes(void)
|
||||
{
|
||||
|
@ -36,24 +36,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
|
||||
/*
|
||||
* Test for equality with two special rules:
|
||||
* fpequal(NaN, NaN) is true
|
||||
* fpequal(+0.0, -0.0) is false
|
||||
*/
|
||||
static inline int
|
||||
fpequal(long double x, long double y)
|
||||
{
|
||||
|
||||
return ((x == y && !signbit(x) == !signbit(y))
|
||||
|| (isnan(x) && isnan(y)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether func(x, y) has the expected result, and make sure no
|
||||
* exceptions are raised.
|
||||
|
@ -38,28 +38,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#define OPT_INVALID (ALL_STD_EXCEPT & ~FE_INVALID)
|
||||
#define OPT_INEXACT (ALL_STD_EXCEPT & ~FE_INEXACT)
|
||||
#define FLT_ULP() ldexpl(1.0, 1 - FLT_MANT_DIG)
|
||||
#define DBL_ULP() ldexpl(1.0, 1 - DBL_MANT_DIG)
|
||||
#define LDBL_ULP() ldexpl(1.0, 1 - LDBL_MANT_DIG)
|
||||
#include "test-utils.h"
|
||||
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#pragma STDC CX_LIMITED_RANGE OFF
|
||||
|
||||
/* Flags that determine whether to check the signs of the result. */
|
||||
#define CS_REAL 1
|
||||
#define CS_IMAG 2
|
||||
#define CS_BOTH (CS_REAL | CS_IMAG)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define debug(...) (void)0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Test that a function returns the correct value and sets the
|
||||
* exception flags correctly. The exceptmask specifies which
|
||||
@ -78,8 +61,8 @@ __FBSDID("$FreeBSD$");
|
||||
debug(" testing %s(%Lg + %Lg I) == %Lg + %Lg I\n", #func, \
|
||||
creall(_d), cimagl(_d), creall(result), cimagl(result)); \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(cfpequal((func)(_d), (result), (checksign))); \
|
||||
assert(((func), fetestexcept(exceptmask) == (excepts))); \
|
||||
assert(cfpequal_cs((func)(_d), (result), (checksign))); \
|
||||
assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
@ -90,7 +73,7 @@ __FBSDID("$FreeBSD$");
|
||||
volatile long double complex _d = z; \
|
||||
debug(" testing %s(%Lg + %Lg I) ~= %Lg + %Lg I\n", #func, \
|
||||
creall(_d), cimagl(_d), creall(result), cimagl(result)); \
|
||||
assert(cfpequal_tol((func)(_d), (result), (tol))); \
|
||||
assert(cfpequal_tol((func)(_d), (result), (tol), CS_BOTH)); \
|
||||
} while (0)
|
||||
|
||||
/* These wrappers apply the identities f(conj(z)) = conj(f(z)). */
|
||||
@ -138,59 +121,6 @@ static const long double
|
||||
pi = 3.14159265358979323846264338327950280L,
|
||||
c3pi = 9.42477796076937971538793014983850839L;
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
* If checksign is 0, we compare the absolute values instead.
|
||||
*/
|
||||
static int
|
||||
fpequal(long double x, long double y, int checksign)
|
||||
{
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (checksign)
|
||||
return (x == y && !signbit(x) == !signbit(y));
|
||||
else
|
||||
return (fabsl(x) == fabsl(y));
|
||||
}
|
||||
|
||||
static int
|
||||
fpequal_tol(long double x, long double y, long double tol)
|
||||
{
|
||||
fenv_t env;
|
||||
int ret;
|
||||
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (!signbit(x) != !signbit(y))
|
||||
return (0);
|
||||
if (x == y)
|
||||
return (1);
|
||||
if (tol == 0 || y == 0.0)
|
||||
return (0);
|
||||
|
||||
/* Hard case: need to check the tolerance. */
|
||||
feholdexcept(&env);
|
||||
ret = fabsl(x - y) <= fabsl(y * tol);
|
||||
fesetenv(&env);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal(long double complex x, long double complex y, int checksign)
|
||||
{
|
||||
return (fpequal(creal(x), creal(y), checksign & CS_REAL)
|
||||
&& fpequal(cimag(x), cimag(y), checksign & CS_IMAG));
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal_tol(long double complex x, long double complex y, long double tol)
|
||||
{
|
||||
return (fpequal_tol(creal(x), creal(y), tol)
|
||||
&& fpequal_tol(cimag(x), cimag(y), tol));
|
||||
}
|
||||
|
||||
|
||||
/* Tests for 0 */
|
||||
void
|
||||
|
@ -39,8 +39,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
#define LEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
@ -58,8 +57,8 @@ __FBSDID("$FreeBSD$");
|
||||
#define test_tol(func, x, result, tol, excepts) do { \
|
||||
volatile long double _in = (x), _out = (result); \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(fpequal(func(_in), _out, (tol))); \
|
||||
assert((func, fetestexcept(ALL_STD_EXCEPT) == (excepts))); \
|
||||
assert(fpequal_tol(func(_in), _out, (tol), CS_BOTH)); \
|
||||
assert(((void)func, fetestexcept(ALL_STD_EXCEPT) == (excepts))); \
|
||||
} while (0)
|
||||
#define test(func, x, result, excepts) \
|
||||
test_tol(func, (x), (result), 0, (excepts))
|
||||
@ -78,8 +77,8 @@ __FBSDID("$FreeBSD$");
|
||||
#define test2_tol(func, y, x, result, tol, excepts) do { \
|
||||
volatile long double _iny = (y), _inx = (x), _out = (result); \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(fpequal(func(_iny, _inx), _out, (tol))); \
|
||||
assert((func, fetestexcept(ALL_STD_EXCEPT) == (excepts))); \
|
||||
assert(fpequal_tol(func(_iny, _inx), _out, (tol), CS_BOTH)); \
|
||||
assert(((void)func, fetestexcept(ALL_STD_EXCEPT) == (excepts))); \
|
||||
} while (0)
|
||||
#define test2(func, y, x, result, excepts) \
|
||||
test2_tol(func, (y), (x), (result), 0, (excepts))
|
||||
@ -104,33 +103,6 @@ c7pi = 2.19911485751285526692385036829565196e+01L,
|
||||
c5pio3 = 5.23598775598298873077107230546583851e+00L,
|
||||
sqrt2m1 = 4.14213562373095048801688724209698081e-01L;
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal to within a relative error of tol,
|
||||
* with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
*/
|
||||
int
|
||||
fpequal(long double x, long double y, long double tol)
|
||||
{
|
||||
fenv_t env;
|
||||
int ret;
|
||||
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (!signbit(x) != !signbit(y))
|
||||
return (0);
|
||||
if (x == y)
|
||||
return (1);
|
||||
if (tol == 0)
|
||||
return (0);
|
||||
|
||||
/* Hard case: need to check the tolerance. */
|
||||
feholdexcept(&env);
|
||||
ret = fabsl(x - y) <= fabsl(y * tol);
|
||||
fesetenv(&env);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test special case inputs in asin(), acos() and atan(): signed
|
||||
|
@ -41,8 +41,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
|
||||
@ -63,7 +62,7 @@ __FBSDID("$FreeBSD$");
|
||||
volatile long double _d = x; \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(fpequal((func)(_d), (result))); \
|
||||
assert(((func), fetestexcept(exceptmask) == (excepts))); \
|
||||
assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
|
||||
} while (0)
|
||||
|
||||
/* Test all the functions that compute log(x). */
|
||||
@ -82,17 +81,6 @@ __FBSDID("$FreeBSD$");
|
||||
test(log1pf, x, result, exceptmask, excepts); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
*/
|
||||
int
|
||||
fpequal(long double x, long double y)
|
||||
{
|
||||
return ((x == y && !signbit(x) == !signbit(y)) || isnan(x) && isnan(y));
|
||||
}
|
||||
|
||||
void
|
||||
run_generic_tests(void)
|
||||
{
|
||||
|
@ -40,8 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
static int testnum;
|
||||
|
||||
@ -49,6 +48,14 @@ static const int rmodes[] = {
|
||||
FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO,
|
||||
};
|
||||
|
||||
/* Make sure we're testing the library, not some broken compiler built-ins. */
|
||||
double (*libnearbyint)(double) = nearbyint;
|
||||
float (*libnearbyintf)(float) = nearbyintf;
|
||||
long double (*libnearbyintl)(long double) = nearbyintl;
|
||||
#define nearbyintf libnearbyintf
|
||||
#define nearbyint libnearbyint
|
||||
#define nearbyintl libnearbyintl
|
||||
|
||||
static const struct {
|
||||
float in;
|
||||
float out[3]; /* one answer per rounding mode except towardzero */
|
||||
@ -64,19 +71,6 @@ static const struct {
|
||||
|
||||
static const int ntests = sizeof(tests) / sizeof(tests[0]);
|
||||
|
||||
/*
|
||||
* Compare d1 and d2 using special rules: NaN == NaN and +0 != -0.
|
||||
* Fail an assertion if they differ.
|
||||
*/
|
||||
static int
|
||||
fpequal(long double d1, long double d2)
|
||||
{
|
||||
|
||||
if (d1 != d2)
|
||||
return (isnan(d1) && isnan(d2));
|
||||
return (copysignl(1.0, d1) == copysignl(1.0, d2));
|
||||
}
|
||||
|
||||
/* Get the appropriate result for the current rounding mode. */
|
||||
static float
|
||||
get_output(int testindex, int rmodeindex, int negative)
|
||||
@ -107,7 +101,7 @@ test_nearby(int testindex)
|
||||
|
||||
in = tests[testindex].in;
|
||||
out = get_output(testindex, i, 0);
|
||||
assert(fpequal(out, nearbyintf(in)));
|
||||
assert(fpequal(out, libnearbyintf(in)));
|
||||
assert(fpequal(out, nearbyint(in)));
|
||||
assert(fpequal(out, nearbyintl(in)));
|
||||
assert(fetestexcept(ALL_STD_EXCEPT) == 0);
|
||||
|
@ -41,8 +41,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID |\
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
#define test(exp, ans, ex) do { \
|
||||
double __ans = (ans); \
|
||||
feclearexcept(ALL_STD_EXCEPT); \
|
||||
@ -235,7 +235,7 @@ _testl(const char *exp, int line, long double actual, long double expected,
|
||||
int actual_except;
|
||||
|
||||
actual_except = fetestexcept(ALL_STD_EXCEPT);
|
||||
if (actual != expected && !(isnan(actual) && isnan(expected))) {
|
||||
if (!fpequal(actual, expected)) {
|
||||
fprintf(stderr, "%d: %s returned %La, expecting %La\n",
|
||||
line, exp, actual, expected);
|
||||
abort();
|
||||
|
@ -42,8 +42,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#include "test-utils.h"
|
||||
|
||||
#define LEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
@ -66,7 +65,7 @@ __FBSDID("$FreeBSD$");
|
||||
volatile long double _d = x; \
|
||||
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
|
||||
assert(fpequal((func)(_d), (result))); \
|
||||
assert(((func), fetestexcept(exceptmask) == (excepts))); \
|
||||
assert(((void)(func), fetestexcept(exceptmask) == (excepts))); \
|
||||
} while (0)
|
||||
|
||||
#define testall(prefix, x, result, exceptmask, excepts) do { \
|
||||
@ -80,19 +79,6 @@ __FBSDID("$FreeBSD$");
|
||||
test(prefix##f, x, (float)result, exceptmask, excepts); \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
*/
|
||||
int
|
||||
fpequal(long double x, long double y)
|
||||
{
|
||||
return ((x == y && !signbit(x) == !signbit(y)) || isnan(x) && isnan(y));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test special cases in sin(), cos(), and tan().
|
||||
*/
|
||||
|
174
tools/regression/lib/msun/test-utils.h
Normal file
174
tools/regression/lib/msun/test-utils.h
Normal file
@ -0,0 +1,174 @@
|
||||
/*-
|
||||
* Copyright (c) 2005-2013 David Schultz <das@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _TEST_UTILS_H_
|
||||
#define _TEST_UTILS_H_
|
||||
|
||||
#include <complex.h>
|
||||
#include <fenv.h>
|
||||
|
||||
/*
|
||||
* Implementations are permitted to define additional exception flags
|
||||
* not specified in the standard, so it is not necessarily true that
|
||||
* FE_ALL_EXCEPT == ALL_STD_EXCEPT.
|
||||
*/
|
||||
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
|
||||
FE_OVERFLOW | FE_UNDERFLOW)
|
||||
#define OPT_INVALID (ALL_STD_EXCEPT & ~FE_INVALID)
|
||||
#define OPT_INEXACT (ALL_STD_EXCEPT & ~FE_INEXACT)
|
||||
#define FLT_ULP() ldexpl(1.0, 1 - FLT_MANT_DIG)
|
||||
#define DBL_ULP() ldexpl(1.0, 1 - DBL_MANT_DIG)
|
||||
#define LDBL_ULP() ldexpl(1.0, 1 - LDBL_MANT_DIG)
|
||||
|
||||
/*
|
||||
* Flags that control the behavior of various fpequal* functions.
|
||||
* XXX This is messy due to merging various notions of "close enough"
|
||||
* that are best suited for different functions.
|
||||
*
|
||||
* CS_REAL
|
||||
* CS_IMAG
|
||||
* CS_BOTH
|
||||
* (cfpequal_cs, fpequal_tol, cfpequal_tol) Whether to check the sign of
|
||||
* the real part of the result, the imaginary part, or both.
|
||||
*
|
||||
* FPE_ABS_ZERO
|
||||
* (fpequal_tol, cfpequal_tol) If set, treats the tolerance as an absolute
|
||||
* tolerance when the expected value is 0. This is useful when there is
|
||||
* round-off error in the input, e.g., cos(Pi/2) ~= 0.
|
||||
*/
|
||||
#define CS_REAL 0x01
|
||||
#define CS_IMAG 0x02
|
||||
#define CS_BOTH (CS_REAL | CS_IMAG)
|
||||
#define FPE_ABS_ZERO 0x04
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define debug(...) (void)0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XXX The ancient version of gcc in the base system doesn't support CMPLXL,
|
||||
* but we can fake it most of the time.
|
||||
*/
|
||||
#ifndef CMPLXL
|
||||
static inline long double complex
|
||||
CMPLXL(long double x, long double y)
|
||||
{
|
||||
long double complex z;
|
||||
|
||||
__real__ z = x;
|
||||
__imag__ z = y;
|
||||
return (z);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compare d1 and d2 using special rules: NaN == NaN and +0 != -0.
|
||||
* Fail an assertion if they differ.
|
||||
*/
|
||||
static int
|
||||
fpequal(long double d1, long double d2)
|
||||
{
|
||||
|
||||
if (d1 != d2)
|
||||
return (isnan(d1) && isnan(d2));
|
||||
return (copysignl(1.0, d1) == copysignl(1.0, d2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether x and y are equal, with two special rules:
|
||||
* +0.0 != -0.0
|
||||
* NaN == NaN
|
||||
* If checksign is 0, we compare the absolute values instead.
|
||||
*/
|
||||
static int
|
||||
fpequal_cs(long double x, long double y, int checksign)
|
||||
{
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (checksign)
|
||||
return (x == y && !signbit(x) == !signbit(y));
|
||||
else
|
||||
return (fabsl(x) == fabsl(y));
|
||||
}
|
||||
|
||||
static int
|
||||
fpequal_tol(long double x, long double y, long double tol, unsigned int flags)
|
||||
{
|
||||
fenv_t env;
|
||||
int ret;
|
||||
|
||||
if (isnan(x) && isnan(y))
|
||||
return (1);
|
||||
if (!signbit(x) != !signbit(y) && (flags & CS_BOTH))
|
||||
return (0);
|
||||
if (x == y)
|
||||
return (1);
|
||||
if (tol == 0)
|
||||
return (0);
|
||||
|
||||
/* Hard case: need to check the tolerance. */
|
||||
feholdexcept(&env);
|
||||
/*
|
||||
* For our purposes here, if y=0, we interpret tol as an absolute
|
||||
* tolerance. This is to account for roundoff in the input, e.g.,
|
||||
* cos(Pi/2) ~= 0.
|
||||
*/
|
||||
if ((flags & FPE_ABS_ZERO) && y == 0.0)
|
||||
ret = fabsl(x - y) <= fabsl(tol);
|
||||
else
|
||||
ret = fabsl(x - y) <= fabsl(y * tol);
|
||||
fesetenv(&env);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal(long double complex d1, long double complex d2)
|
||||
{
|
||||
|
||||
return (fpequal(creall(d1), creall(d2)) &&
|
||||
fpequal(cimagl(d1), cimagl(d2)));
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal_cs(long double complex x, long double complex y, int checksign)
|
||||
{
|
||||
return (fpequal_cs(creal(x), creal(y), checksign)
|
||||
&& fpequal_cs(cimag(x), cimag(y), checksign));
|
||||
}
|
||||
|
||||
static int
|
||||
cfpequal_tol(long double complex x, long double complex y, long double tol,
|
||||
unsigned int flags)
|
||||
{
|
||||
return (fpequal_tol(creal(x), creal(y), tol, flags)
|
||||
&& fpequal_tol(cimag(x), cimag(y), tol, flags));
|
||||
}
|
||||
|
||||
#endif /* _TEST_UTILS_H_ */
|
Loading…
Reference in New Issue
Block a user