#include <assert.h>
#include <fenv.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
FE_OVERFLOW | FE_UNDERFLOW)
#pragma STDC FENV_ACCESS ON
#define test(func, x, result, exceptmask, excepts) do { \
volatile long double _d = x; \
assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
assert(fpequal((func)(_d), (result))); \
assert(((func), fetestexcept(exceptmask) == (excepts))); \
} while (0)
#define testall0(x, result, exceptmask, excepts) do { \
test(log, x, result, exceptmask, excepts); \
test(logf, x, result, exceptmask, excepts); \
test(log2, x, result, exceptmask, excepts); \
test(log2f, x, result, exceptmask, excepts); \
test(log10, x, result, exceptmask, excepts); \
test(log10f, x, result, exceptmask, excepts); \
} while (0)
#define testall1(x, result, exceptmask, excepts) do { \
test(log1p, x, result, exceptmask, excepts); \
test(log1pf, x, result, exceptmask, excepts); \
} while (0)
int
fpequal(long double x, long double y)
{
return ((x == y && !signbit(x) == !signbit(y)) || isnan(x) && isnan(y));
}
void
run_generic_tests(void)
{
testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
testall1(-0.0, -0.0, ALL_STD_EXCEPT, 0);
testall0(NAN, NAN, ALL_STD_EXCEPT, 0);
testall1(NAN, NAN, ALL_STD_EXCEPT, 0);
testall0(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
testall1(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
testall0(-INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
testall1(-INFINITY, NAN, ALL_STD_EXCEPT, FE_INVALID);
testall0(-1.0, NAN, ALL_STD_EXCEPT, FE_INVALID);
testall1(-1.5, NAN, ALL_STD_EXCEPT, FE_INVALID);
testall0(0.0, -INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_DIVBYZERO);
testall0(-0.0, -INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_DIVBYZERO);
testall1(-1.0, -INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_DIVBYZERO);
}
void
run_log2_tests(void)
{
int i;
feclearexcept(FE_ALL_EXCEPT);
for (i = FLT_MIN_EXP - FLT_MANT_DIG; i < FLT_MAX_EXP; i++) {
assert(log2f(ldexpf(1.0, i)) == i);
assert(fetestexcept(ALL_STD_EXCEPT) == 0);
}
for (i = DBL_MIN_EXP - DBL_MANT_DIG; i < DBL_MAX_EXP; i++) {
assert(log2(ldexp(1.0, i)) == i);
assert(fetestexcept(ALL_STD_EXCEPT) == 0);
}
}
void
run_roundingmode_tests(void)
{
fesetround(FE_DOWNWARD);
testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
fesetround(FE_TOWARDZERO);
testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
fesetround(FE_UPWARD);
testall0(1.0, 0.0, ALL_STD_EXCEPT, 0);
testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
testall1(-0.0, -0.0, ALL_STD_EXCEPT, 0);
fesetround(FE_TONEAREST);
}
int
main(int argc, char *argv[])
{
printf("1..3\n");
run_generic_tests();
printf("ok 1 - logarithm\n");
run_log2_tests();
printf("ok 2 - logarithm\n");
run_roundingmode_tests();
printf("ok 3 - logarithm\n");
return (0);
}