void run_inf_opt_test(double d) { test("optimizations don't break infinities", fpequal(d / d, NAN) && fpequal(0.0 * d, NAN)); }
void run_zero_opt_test(double d1, double d2) { test("optimizations don't break the sign of 0", fpequal(d1 - d2, 0.0) && fpequal(-d1 + 0.0, 0.0) && fpequal(-d1 - d2, -0.0) && fpequal(-(d1 - d2), -0.0) && fpequal(-d1 - (-d2), 0.0)); }
static void _testl(const char *exp, int line, long double actual, long double expected, int except) { int actual_except; actual_except = fetestexcept(ALL_STD_EXCEPT); if (!fpequal(actual, expected)) { fprintf(stderr, "%d: %s returned %La, expecting %La\n", line, exp, actual, expected); abort(); } if (actual_except != except) { fprintf(stderr, "%d: %s raised 0x%x, expecting 0x%x\n", line, exp, actual_except, except); abort(); } }
static void testit(int testnum, float in, float out) { feclearexcept(ALL_STD_EXCEPT); assert(fpequal(out, nearbyintf(in))); assert(fpequal(-out, nearbyintf(-in))); assert(fetestexcept(ALL_STD_EXCEPT) == 0); assert(fpequal(out, nearbyint(in))); assert(fpequal(-out, nearbyint(-in))); assert(fetestexcept(ALL_STD_EXCEPT) == 0); assert(fpequal(out, nearbyintl(in))); assert(fpequal(-out, nearbyintl(-in))); assert(fetestexcept(ALL_STD_EXCEPT) == 0); printf("ok %d\t\t# nearbyint(%g)\n", testnum, in); }
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)); }
void run_tests(void) { volatile long double vld; long double ld; volatile double vd; double d; volatile float vf; float f; int x; test("sign bits", fpequal(-0.0, -0.0) && !fpequal(0.0, -0.0)); vd = NAN; test("NaN equality", fpequal(NAN, NAN) && NAN != NAN && vd != vd); feclearexcept(ALL_STD_EXCEPT); test("NaN comparison returns false", !(vd <= vd)); /* * XXX disabled; gcc/amd64 botches this IEEE 754 requirement by * emitting ucomisd instead of comisd. */ skiptest("FENV_ACCESS: NaN comparison raises invalid exception", fetestexcept(ALL_STD_EXCEPT) == FE_INVALID); vd = 0.0; run_zero_opt_test(vd, vd); vd = INFINITY; run_inf_opt_test(vd); feclearexcept(ALL_STD_EXCEPT); vd = INFINITY; x = (int)vd; /* XXX disabled (works with -O0); gcc doesn't support FENV_ACCESS */ skiptest("FENV_ACCESS: Inf->int conversion raises invalid exception", fetestexcept(ALL_STD_EXCEPT) == FE_INVALID); /* Raising an inexact exception here is an IEEE-854 requirement. */ feclearexcept(ALL_STD_EXCEPT); vd = 0.75; x = (int)vd; test("0.75->int conversion rounds toward 0, raises inexact exception", x == 0 && fetestexcept(ALL_STD_EXCEPT) == FE_INEXACT); feclearexcept(ALL_STD_EXCEPT); vd = -42.0; x = (int)vd; test("-42.0->int conversion is exact, raises no exception", x == -42 && fetestexcept(ALL_STD_EXCEPT) == 0); feclearexcept(ALL_STD_EXCEPT); x = (int)INFINITY; /* XXX disabled; gcc doesn't support FENV_ACCESS */ skiptest("FENV_ACCESS: const Inf->int conversion raises invalid", fetestexcept(ALL_STD_EXCEPT) == FE_INVALID); feclearexcept(ALL_STD_EXCEPT); x = (int)0.5; /* XXX disabled; gcc doesn't support FENV_ACCESS */ skiptest("FENV_ACCESS: const double->int conversion raises inexact", x == 0 && fetestexcept(ALL_STD_EXCEPT) == FE_INEXACT); test("compile-time constants don't have too much precision", one_f == 1.0L && one_d == 1.0L && one_ld == 1.0L); test("const minimum rounding precision", 1.0F + FLT_EPSILON != 1.0F && 1.0 + DBL_EPSILON != 1.0 && 1.0L + LDBL_EPSILON != 1.0L); /* It isn't the compiler's fault if this fails on FreeBSD/i386. */ vf = FLT_EPSILON; vd = DBL_EPSILON; vld = LDBL_EPSILON; test("runtime minimum rounding precision", 1.0F + vf != 1.0F && 1.0 + vd != 1.0 && 1.0L + vld != 1.0L); test("explicit float to float conversion discards extra precision", (float)(1.0F + FLT_EPSILON * 0.5F) == 1.0F && (float)(1.0F + vf * 0.5F) == 1.0F); test("explicit double to float conversion discards extra precision", (float)(1.0 + FLT_EPSILON * 0.5) == 1.0F && (float)(1.0 + vf * 0.5) == 1.0F); test("explicit ldouble to float conversion discards extra precision", (float)(1.0L + FLT_EPSILON * 0.5L) == 1.0F && (float)(1.0L + vf * 0.5L) == 1.0F); test("explicit double to double conversion discards extra precision", (double)(1.0 + DBL_EPSILON * 0.5) == 1.0 && (double)(1.0 + vd * 0.5) == 1.0); test("explicit ldouble to double conversion discards extra precision", (double)(1.0L + DBL_EPSILON * 0.5L) == 1.0 && (double)(1.0L + vd * 0.5L) == 1.0); /* * FLT_EVAL_METHOD > 1 implies that float expressions are always * evaluated in double precision or higher, but some compilers get * this wrong when registers spill to memory. The following expression * forces a spill when there are at most 8 FP registers. */ test("implicit promption to double or higher precision is consistent", #if FLT_EVAL_METHOD == 1 || FLT_EVAL_METHOD == 2 || defined(__i386__) TWICE(TWICE(TWICE(TWICE(TWICE( TWICE(TWICE(TWICE(TWICE(1.0F + vf * 0.5F))))))))) == (1.0 + FLT_EPSILON * 0.5) * 512.0 #else 1 #endif ); f = 1.0 + FLT_EPSILON * 0.5; d = 1.0L + DBL_EPSILON * 0.5L; test("const assignment discards extra precision", f == 1.0F && d == 1.0); f = 1.0 + vf * 0.5; d = 1.0L + vd * 0.5L; test("variable assignment discards explicit extra precision", f == 1.0F && d == 1.0); f = 1.0F + vf * 0.5F; d = 1.0 + vd * 0.5; test("variable assignment discards implicit extra precision", f == 1.0F && d == 1.0); test("return discards extra precision", tofloat(1.0 + vf * 0.5) == 1.0F && todouble(1.0L + vd * 0.5L) == 1.0); fesetround(FE_UPWARD); /* XXX disabled (works with -frounding-math) */ skiptest("FENV_ACCESS: constant arithmetic respects rounding mode", 1.0F + FLT_MIN == 1.0F + FLT_EPSILON && 1.0 + DBL_MIN == 1.0 + DBL_EPSILON && 1.0L + LDBL_MIN == 1.0L + LDBL_EPSILON); fesetround(FE_TONEAREST); ld = vld * 0.5; test("associativity is respected", 1.0L + ld + (LDBL_EPSILON * 0.5) == 1.0L && 1.0L + (LDBL_EPSILON * 0.5) + ld == 1.0L && ld + 1.0 + (LDBL_EPSILON * 0.5) == 1.0L && ld + (LDBL_EPSILON * 0.5) + 1.0 == 1.0L + LDBL_EPSILON); }
int main(int argc, char *argv[]) { static const int ntests = sizeof(tests) / sizeof(tests[0]) / 2; complex float in; complex long double expected; int i; printf("1..%d\n", ntests * 3); for (i = 0; i < ntests; i++) { __real__ expected = __real__ in = tests[2 * i]; __imag__ in = tests[2 * i + 1]; __imag__ expected = -cimag(in); assert(fpequal(libcrealf(in), __real__ in)); assert(fpequal(libcreal(in), __real__ in)); assert(fpequal(libcreall(in), __real__ in)); assert(fpequal(libcimagf(in), __imag__ in)); assert(fpequal(libcimag(in), __imag__ in)); assert(fpequal(libcimagl(in), __imag__ in)); feclearexcept(FE_ALL_EXCEPT); if (!cfpequal(libconjf(in), expected)) { printf("not ok %d\t# conjf(%#.2g + %#.2gI): " "wrong value\n", 3 * i + 1, creal(in), cimag(in)); } else if (fetestexcept(FE_ALL_EXCEPT)) { printf("not ok %d\t# conjf(%#.2g + %#.2gI): " "threw an exception\n", 3 * i + 1, creal(in), cimag(in)); } else { printf("ok %d\t\t# conjf(%#.2g + %#.2gI)\n", 3 * i + 1, creal(in), cimag(in)); } feclearexcept(FE_ALL_EXCEPT); if (!cfpequal(libconj(in), expected)) { printf("not ok %d\t# conj(%#.2g + %#.2gI): " "wrong value\n", 3 * i + 2, creal(in), cimag(in)); } else if (fetestexcept(FE_ALL_EXCEPT)) { printf("not ok %d\t# conj(%#.2g + %#.2gI): " "threw an exception\n", 3 * i + 2, creal(in), cimag(in)); } else { printf("ok %d\t\t# conj(%#.2g + %#.2gI)\n", 3 * i + 2, creal(in), cimag(in)); } feclearexcept(FE_ALL_EXCEPT); if (!cfpequal(libconjl(in), expected)) { printf("not ok %d\t# conjl(%#.2g + %#.2gI): " "wrong value\n", 3 * i + 3, creal(in), cimag(in)); } else if (fetestexcept(FE_ALL_EXCEPT)) { printf("not ok %d\t# conjl(%#.2g + %#.2gI): " "threw an exception\n", 3 * i + 3, creal(in), cimag(in)); } else { printf("ok %d\t\t# conjl(%#.2g + %#.2gI)\n", 3 * i + 3, creal(in), cimag(in)); } } return (0); }