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