diff --git a/src/math/fpclassify.c b/src/math/fpclassify.c new file mode 100644 index 0000000..8a43cd6 --- /dev/null +++ b/src/math/fpclassify.c @@ -0,0 +1,125 @@ +#include +#include + +#define T(a,b) {__LINE__, a, b}, +#define length(a) (sizeof(a)/sizeof*(a)) + +static struct { + int line; + float f; + int class; +} tf[] = { + T(0.0/0.0, FP_NAN) + T(-0.0/0.0, FP_NAN) + T(1/0.0, FP_INFINITE) + T(-1/0.0, FP_INFINITE) + T(0x1.ffffp127, FP_NORMAL) + T(-0x1.ffffp127, FP_NORMAL) + T(0x1p-127, FP_SUBNORMAL) + T(-0x1p-127, FP_SUBNORMAL) + T(0.0, FP_ZERO) + T(-0.0, FP_ZERO) + T(3.14, FP_NORMAL) + T(-42, FP_NORMAL) +}; + +static struct { + int line; + double f; + int class; +} td[] = { + T(0.0/0.0, FP_NAN) + T(-0.0/0.0, FP_NAN) + T(1/0.0, FP_INFINITE) + T(-1/0.0, FP_INFINITE) + T(0x1.ffffp1023, FP_NORMAL) + T(-0x1.ffffp1023, FP_NORMAL) + T(0x1p-1023, FP_SUBNORMAL) + T(-0x1p-1023, FP_SUBNORMAL) + T(0.0, FP_ZERO) + T(-0.0, FP_ZERO) + T(3.14, FP_NORMAL) + T(-42, FP_NORMAL) +}; + +static struct { + int line; + long double f; + int class; +} tl[] = { + T(0.0/0.0, FP_NAN) + T(-0.0/0.0, FP_NAN) + T(1/0.0, FP_INFINITE) + T(-1/0.0, FP_INFINITE) + T(0x1.ffffp16383L, FP_NORMAL) + T(-0x1.ffffp16383L, FP_NORMAL) + T(0x1p-16383L, FP_SUBNORMAL) + T(-0x1p-16383L, FP_SUBNORMAL) + T(0.0, FP_ZERO) + T(-0.0, FP_ZERO) + T(3.14, FP_NORMAL) + T(-42, FP_NORMAL) +}; + +static char *strclass(int c) +{ +#define C(n) case n: return #n; + switch (c) { + C(FP_NAN) + C(FP_INFINITE) + C(FP_ZERO) + C(FP_SUBNORMAL) + C(FP_NORMAL) + } + return "invalid"; +} + +#define error(t,c) err++, printf("%s:%d: (at line %d) %La has class %d (%s), but %s returns %d\n", \ + __FILE__, __LINE__, t.line, (long double)t.f, t.class, strclass(t.class), #c, c(t.f)) + +int main() +{ + int i; + int err = 0; + + for (i = 0; i < length(tf); i++) { + if (fpclassify(tf[i].f) != tf[i].class) + error(tf[i], fpclassify); + if (!!isinf(tf[i].f) != (tf[i].class == FP_INFINITE)) + error(tf[i], isinf); + if (!!isnan(tf[i].f) != (tf[i].class == FP_NAN)) + error(tf[i], isnan); + if (!!isnormal(tf[i].f) != (tf[i].class == FP_NORMAL)) + error(tf[i], isnormal); + if (!!isfinite(tf[i].f) != (tf[i].class > FP_INFINITE)) + error(tf[i], isfinite); + } + + for (i = 0; i < length(td); i++) { + if (fpclassify(td[i].f) != td[i].class) + error(td[i], fpclassify); + if (!!isinf(td[i].f) != (td[i].class == FP_INFINITE)) + error(td[i], isinf); + if (!!isnan(td[i].f) != (td[i].class == FP_NAN)) + error(td[i], isnan); + if (!!isnormal(td[i].f) != (td[i].class == FP_NORMAL)) + error(td[i], isnormal); + if (!!isfinite(td[i].f) != (td[i].class > FP_INFINITE)) + error(td[i], isfinite); + } + + for (i = 0; i < length(tl); i++) { + if (fpclassify(tl[i].f) != tl[i].class) + error(tl[i], fpclassify); + if (!!isinf(tl[i].f) != (tl[i].class == FP_INFINITE)) + error(tl[i], isinf); + if (!!isnan(tl[i].f) != (tl[i].class == FP_NAN)) + error(tl[i], isnan); + if (!!isnormal(tl[i].f) != (tl[i].class == FP_NORMAL)) + error(tl[i], isnormal); + if (!!isfinite(tl[i].f) != (tl[i].class > FP_INFINITE)) + error(tl[i], isfinite); + } + + return !!err; +}