Blame src/math/fenv.c

Szabolcs Nagy ae0f0f
#include <stdint.h>
Szabolcs Nagy ae0f0f
#include <stdio.h>
Szabolcs Nagy ae0f0f
#include <stdarg.h>
Szabolcs Nagy cfa23c
#include "mtest.h"
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
static int test_status;
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
#define error(...) print(__FILE__, __LINE__, __VA_ARGS__)
Szabolcs Nagy ae0f0f
static void print(char *f, int l, char *fmt, ...)
Szabolcs Nagy ae0f0f
{
Szabolcs Nagy ae0f0f
	test_status = 1;
Szabolcs Nagy ae0f0f
	va_list ap;
Szabolcs Nagy ae0f0f
	printf("%s:%d: ", f, l);
Szabolcs Nagy ae0f0f
	va_start(ap, fmt);
Szabolcs Nagy ae0f0f
	vprintf(fmt, ap);
Szabolcs Nagy ae0f0f
	va_end(ap);
Szabolcs Nagy ae0f0f
}
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
#define F(n) {#n, n}
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
static struct {
Szabolcs Nagy ae0f0f
	char *name;
Szabolcs Nagy ae0f0f
	int i;
Szabolcs Nagy ae0f0f
} te[] = {
Szabolcs Nagy ae0f0f
#ifdef FE_DIVBYZERO
Szabolcs Nagy ae0f0f
	F(FE_DIVBYZERO),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy ae0f0f
#ifdef FE_INEXACT
Szabolcs Nagy ae0f0f
	F(FE_INEXACT),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy ae0f0f
#ifdef FE_INVALID
Szabolcs Nagy ae0f0f
	F(FE_INVALID),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy ae0f0f
#ifdef FE_OVERFLOW
Szabolcs Nagy ae0f0f
	F(FE_OVERFLOW),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy ae0f0f
#ifdef FE_UNDERFLOW
Szabolcs Nagy ae0f0f
	F(FE_UNDERFLOW),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy 21a846
	{0, 0}
Szabolcs Nagy ae0f0f
};
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
static void test_except()
Szabolcs Nagy ae0f0f
{
Szabolcs Nagy ae0f0f
	#pragma STDC FENV_ACCESS ON
Szabolcs Nagy ae0f0f
	int i,r;
Szabolcs Nagy 4b4849
	fenv_t env;
Szabolcs Nagy ae0f0f
Szabolcs Nagy 21a846
	for (i=0; te[i].i; i++) {
Szabolcs Nagy ae0f0f
		feclearexcept(FE_ALL_EXCEPT);
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
		r = feraiseexcept(te[i].i);
Szabolcs Nagy ae0f0f
		if (r)
Szabolcs Nagy ae0f0f
			error("feraiseexcept(%s) returned %d\n", te[i].name, r);
Szabolcs Nagy ae0f0f
		r = fetestexcept(FE_ALL_EXCEPT);
Szabolcs Nagy c8999d
		if (r != te[i].i) {
Szabolcs Nagy c8999d
#if defined FE_OVERFLOW && defined FE_INEXACT
Szabolcs Nagy 8b61f8
			if (te[i].i == FE_OVERFLOW && r == (FE_OVERFLOW|FE_INEXACT))
Szabolcs Nagy c8999d
				continue;
Szabolcs Nagy c8999d
#endif
Szabolcs Nagy c8999d
#if defined FE_UNDERFLOW && defined FE_INEXACT
Szabolcs Nagy 8b61f8
			if (te[i].i == FE_UNDERFLOW && r == (FE_UNDERFLOW|FE_INEXACT))
Szabolcs Nagy c8999d
				continue;
Szabolcs Nagy c8999d
#endif
Szabolcs Nagy ae0f0f
			error("feraiseexcept(%s) want %d got %d\n",
Szabolcs Nagy ae0f0f
				te[i].name, te[i].i, r);
Szabolcs Nagy c8999d
		}
Szabolcs Nagy ae0f0f
	}
Szabolcs Nagy 4b4849
Szabolcs Nagy 21a846
	r = feraiseexcept(FE_ALL_EXCEPT);
Szabolcs Nagy 21a846
	if (r != 0)
Szabolcs Nagy 21a846
		error("feraisexcept(FE_ALL_EXCEPT) failed\n");
Szabolcs Nagy 4b4849
	r = fegetenv(&env;;
Szabolcs Nagy 4b4849
	if (r != 0)
Szabolcs Nagy 4b4849
		error("fegetenv(&env) = %d\n", r);
Szabolcs Nagy 21a846
	r = fetestexcept(FE_ALL_EXCEPT);
Szabolcs Nagy 21a846
	if (r != FE_ALL_EXCEPT)
Szabolcs Nagy 21a846
		error("fetestexcept failed: got 0x%x, want 0x%x (FE_ALL_ECXEPT)\n", r, FE_ALL_EXCEPT);
Szabolcs Nagy 4b4849
	r = fesetenv(FE_DFL_ENV);
Szabolcs Nagy 4b4849
	if (r != 0)
Szabolcs Nagy 4b4849
		error("fesetenv(FE_DFL_ENV) = %d\n", r);
Szabolcs Nagy 4b4849
	r = fetestexcept(FE_ALL_EXCEPT);
Szabolcs Nagy 4b4849
	if (r != 0)
Szabolcs Nagy 4b4849
		error("fesetenv(FE_DFL_ENV) did not clear exceptions: 0x%x\n", r);
Szabolcs Nagy 4b4849
	r = fesetenv(&env;;
Szabolcs Nagy 4b4849
	if (r != 0)
Szabolcs Nagy 4b4849
		error("fesetenv(&env) = %d\n", r);
Szabolcs Nagy 4b4849
	r = fetestexcept(FE_ALL_EXCEPT);
Szabolcs Nagy 21a846
	if (r != FE_ALL_EXCEPT)
Szabolcs Nagy 4b4849
		error("fesetenv(&env) did not restore exceptions: 0x%x\n", r);
Szabolcs Nagy ae0f0f
}
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
static struct {
Szabolcs Nagy ae0f0f
	char *name;
Szabolcs Nagy ae0f0f
	int i;
Szabolcs Nagy ae0f0f
} tr[] = {
Szabolcs Nagy ae0f0f
	F(FE_TONEAREST),
Szabolcs Nagy ae0f0f
#ifdef FE_UPWARD
Szabolcs Nagy ae0f0f
	F(FE_UPWARD),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy ae0f0f
#ifdef FE_DOWNWARD
Szabolcs Nagy ae0f0f
	F(FE_DOWNWARD),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy ae0f0f
#ifdef FE_TOWARDZERO
Szabolcs Nagy ae0f0f
	F(FE_TOWARDZERO),
Szabolcs Nagy ae0f0f
#endif
Szabolcs Nagy ae0f0f
};
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
static void test_round()
Szabolcs Nagy ae0f0f
{
Szabolcs Nagy ae0f0f
	#pragma STDC FENV_ACCESS ON
Szabolcs Nagy ae0f0f
	int i,r;
Szabolcs Nagy 4b4849
	fenv_t env;
Szabolcs Nagy 6abdab
	volatile float two100 = 0x1p100;
Szabolcs Nagy 6abdab
	volatile float x;
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
	for (i=0; i < sizeof tr/sizeof*tr; i++) {
Szabolcs Nagy ae0f0f
		if (tr[i].i < 0)
Szabolcs Nagy ae0f0f
			error("%s (%d) < 0\n", tr[i].name, tr[i].i);
Szabolcs Nagy ae0f0f
		for (r=0; r < i; r++)
Szabolcs Nagy ae0f0f
			if (tr[r].i == tr[i].i)
Szabolcs Nagy ae0f0f
				error("%s (%d) == %s (%d)\n",
Szabolcs Nagy ae0f0f
					tr[r].name, tr[r].i, tr[i].name, tr[i].i);
Szabolcs Nagy ae0f0f
	}
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
	for (i=0; i < sizeof tr/sizeof*tr; i++) {
Szabolcs Nagy ae0f0f
		r = fesetround(tr[i].i);
Szabolcs Nagy ae0f0f
		if (r != 0)
Szabolcs Nagy 4b4849
			error("fesetround(%s) = %d\n", tr[i].name, r);
Szabolcs Nagy ae0f0f
		r = fegetround();
Szabolcs Nagy ae0f0f
		if (r != tr[i].i)
Szabolcs Nagy 4b4849
			error("fegetround() = 0x%x, wanted 0x%x (%s)\n", r, tr[i].i, tr[i].name);
Szabolcs Nagy ae0f0f
	}
Szabolcs Nagy 4b4849
Szabolcs Nagy 6abdab
#ifdef FE_UPWARD
Szabolcs Nagy 6abdab
	r = fesetround(FE_UPWARD);
Szabolcs Nagy 6abdab
	if (r != 0)
Szabolcs Nagy 6abdab
		error("fesetround(FE_UPWARD) failed\n");
Szabolcs Nagy 6abdab
#endif
Szabolcs Nagy 4b4849
	r = fegetenv(&env;;
Szabolcs Nagy 4b4849
	if (r != 0)
Szabolcs Nagy 4b4849
		error("fegetenv(&env) = %d\n", r);
Szabolcs Nagy 4b4849
	i = fegetround();
Szabolcs Nagy 4b4849
	r = fesetenv(FE_DFL_ENV);
Szabolcs Nagy 4b4849
	if (r != 0)
Szabolcs Nagy 4b4849
		error("fesetenv(FE_DFL_ENV) = %d\n", r);
Szabolcs Nagy 4b4849
	r = fegetround();
Szabolcs Nagy 4b4849
	if (r != FE_TONEAREST)
Szabolcs Nagy 4b4849
		error("fesetenv(FE_DFL_ENV) did not set FE_TONEAREST (0x%x), got 0x%x\n", FE_TONEAREST, r);
Szabolcs Nagy 6abdab
	x = two100 + 1;
Szabolcs Nagy 6abdab
	if (x != two100)
Szabolcs Nagy 6abdab
		error("fesetenv(FE_DFL_ENV) did not set FE_TONEAREST, arithmetics rounds upward\n");
Szabolcs Nagy 6abdab
	x = two100 - 1;
Szabolcs Nagy 6abdab
	if (x != two100)
Szabolcs Nagy 6abdab
		error("fesetenv(FE_DFL_ENV) did not set FE_TONEAREST, arithmetics rounds downward or tozero\n");
Szabolcs Nagy 4b4849
	r = fesetenv(&env;;
Szabolcs Nagy 4b4849
	if (r != 0)
Szabolcs Nagy 4b4849
		error("fesetenv(&env) = %d\n", r);
Szabolcs Nagy 4b4849
	r = fegetround();
Szabolcs Nagy 4b4849
	if (r != i)
Szabolcs Nagy 4b4849
		error("fesetenv(&env) did not restore 0x%x, got 0x%x\n", i, r);
Szabolcs Nagy 6abdab
#ifdef FE_UPWARD
Szabolcs Nagy 6abdab
	x = two100 + 1;
Szabolcs Nagy 6abdab
	if (x == two100)
Szabolcs Nagy 6abdab
		error("fesetenv did not restore upward rounding\n");
Szabolcs Nagy 6abdab
#endif
Szabolcs Nagy 6abdab
Szabolcs Nagy ae0f0f
}
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
/* ieee double precision add operation */
Szabolcs Nagy ae0f0f
static struct dd_d t[] = {
Szabolcs Nagy ae0f0f
T(RN,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
Szabolcs Nagy ae0f0f
T(RN,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RN,                  0x1p+0,              0x1.01p-53,    0x1.0000000000001p+0,       0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RN,                  0x1p+0,                -0x1p-54,                  0x1p+0,          0x1p-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RN,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RN,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RN,                 -0x1p+0,             -0x1.01p-53,   -0x1.0000000000001p+0,      -0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RN,                 -0x1p+0,                 0x1p-54,                 -0x1p+0,         -0x1p-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RN,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
T(RU,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
Szabolcs Nagy ae0f0f
T(RU,                  0x1p+0,                 0x1p-53,    0x1.0000000000001p+0,          0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RU,                  0x1p+0,              0x1.01p-53,    0x1.0000000000001p+0,       0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RU,                  0x1p+0,                -0x1p-54,                  0x1p+0,          0x1p-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RU,                  0x1p+0,             -0x1.01p-54,                  0x1p+0,       0x1.01p-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RU,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RU,                 -0x1p+0,             -0x1.01p-53,                 -0x1p+0,       0x1.01p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RU,                 -0x1p+0,                 0x1p-54,   -0x1.fffffffffffffp-1,          0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RU,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
T(RD,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
Szabolcs Nagy ae0f0f
T(RD,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RD,                  0x1p+0,              0x1.01p-53,                  0x1p+0,      -0x1.01p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RD,                  0x1p+0,                -0x1p-54,    0x1.fffffffffffffp-1,         -0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RD,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RD,                 -0x1p+0,                -0x1p-53,   -0x1.0000000000001p+0,         -0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RD,                 -0x1p+0,             -0x1.01p-53,   -0x1.0000000000001p+0,      -0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RD,                 -0x1p+0,                 0x1p-54,                 -0x1p+0,         -0x1p-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RD,                 -0x1p+0,              0x1.01p-54,                 -0x1p+0,      -0x1.01p-2, INEXACT)
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
T(RZ,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
Szabolcs Nagy ae0f0f
T(RZ,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RZ,                  0x1p+0,              0x1.01p-53,                  0x1p+0,      -0x1.01p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RZ,                  0x1p+0,                -0x1p-54,    0x1.fffffffffffffp-1,         -0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RZ,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
T(RZ,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RZ,                 -0x1p+0,             -0x1.01p-53,                 -0x1p+0,       0x1.01p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RZ,                 -0x1p+0,                 0x1p-54,   -0x1.fffffffffffffp-1,          0x1p-1, INEXACT)
Szabolcs Nagy ae0f0f
T(RZ,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
Szabolcs Nagy ae0f0f
};
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
static void test_round_add(void)
Szabolcs Nagy ae0f0f
{
Szabolcs Nagy ae0f0f
	#pragma STDC FENV_ACCESS ON
Szabolcs Nagy ae0f0f
	double y;
Szabolcs Nagy ae0f0f
	float d;
Szabolcs Nagy ae0f0f
	int i;
Szabolcs Nagy ae0f0f
	struct dd_d *p;
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
	for (i = 0; i < sizeof t/sizeof *t; i++) {
Szabolcs Nagy ae0f0f
		p = t + i;
Szabolcs Nagy ae0f0f
Szabolcs Nagy ae0f0f
		if (p->r < 0)
Szabolcs Nagy ae0f0f
			continue;
Szabolcs Nagy ae0f0f
		fesetround(p->r);
Szabolcs Nagy ae0f0f
		y = p->x + p->x2;
Szabolcs Nagy ae0f0f
		d = ulperr(y, p->y, p->dy);
Szabolcs Nagy ae0f0f
		if (!checkcr(y, p->y, p->r)) {
Szabolcs Nagy ae0f0f
			printf("%s:%d: %s %a+%a want %a got %a ulperr %.3f = %a + %a\n",
Szabolcs Nagy ae0f0f
				p->file, p->line, rstr(p->r), p->x, p->x2, p->y, y, d, d-p->dy, p->dy);
Szabolcs Nagy ae0f0f
			test_status = 1;
Szabolcs Nagy ae0f0f
		}
Szabolcs Nagy ae0f0f
	}
Szabolcs Nagy ae0f0f
}
Szabolcs Nagy ae0f0f
Szabolcs Nagy 21a846
static void test_bad(void)
Szabolcs Nagy 21a846
{
Szabolcs Nagy 21a846
	fexcept_t f;
Szabolcs Nagy 21a846
	int r;
Szabolcs Nagy 21a846
Szabolcs Nagy 705b5a
	r = feclearexcept(FE_ALL_EXCEPT);
Szabolcs Nagy 705b5a
	if (r != 0)
Szabolcs Nagy 705b5a
		error("feclearexcept(FE_ALL_EXCEPT) failed\n");
Szabolcs Nagy 705b5a
	r = fetestexcept(-1);
Szabolcs Nagy 705b5a
	if (r != 0)
Szabolcs Nagy 705b5a
		error("fetestexcept(-1) should return 0 when all exceptions are cleared, got %d\n", r);
Szabolcs Nagy 705b5a
	r = feraiseexcept(1234567|FE_ALL_EXCEPT);
Szabolcs Nagy 705b5a
	if (r != 0)
Szabolcs Nagy 705b5a
		error("feraiseexcept returned non-zero for non-supported exceptions: %d\n", r);
Szabolcs Nagy 705b5a
	r = feclearexcept(1234567|FE_ALL_EXCEPT);
Szabolcs Nagy 705b5a
	if (r != 0)
Szabolcs Nagy 705b5a
		error("feclearexcept returned non-zero for non-supported exceptions: %d\n", r);
Szabolcs Nagy 21a846
	r = fesetround(1234567);
Szabolcs Nagy 21a846
	if (r == 0)
Szabolcs Nagy 21a846
		error("fesetround should fail on invalid rounding mode\n");
Szabolcs Nagy 21a846
	r = fegetexceptflag(&f, 1234567);
Szabolcs Nagy 705b5a
	if (r != 0)
Szabolcs Nagy 705b5a
		error("fegetexceptflag returned non-zero for non-supported exceptions: %d\n", r);
Szabolcs Nagy 21a846
	r = fegetexceptflag(&f, 0);
Szabolcs Nagy 21a846
	if (r != 0)
Szabolcs Nagy 21a846
		error("fegetexceptflag(0) failed\n");
Szabolcs Nagy 21a846
	r = fesetexceptflag(&f, 1234567);
Szabolcs Nagy 705b5a
	if (r != 0)
Szabolcs Nagy 705b5a
		error("fesetexceptflag returned non-zero fir non-supported exceptions: %d\n", r);
Szabolcs Nagy 21a846
}
Szabolcs Nagy 21a846
Szabolcs Nagy ae0f0f
int main(void)
Szabolcs Nagy ae0f0f
{
Szabolcs Nagy ae0f0f
	test_except();
Szabolcs Nagy ae0f0f
	test_round();
Szabolcs Nagy ae0f0f
	test_round_add();
Szabolcs Nagy 21a846
	test_bad();
Szabolcs Nagy ae0f0f
	return test_status;
Szabolcs Nagy ae0f0f
}