91b6378323f07849fcc774a3f78928f8b077aeb6
[libc-test] / src / math / fenv.c
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include "mtest.h"
5
6 static int test_status;
7
8 #define error(...) print(__FILE__, __LINE__, __VA_ARGS__)
9 static void print(char *f, int l, char *fmt, ...)
10 {
11         test_status = 1;
12         va_list ap;
13         printf("%s:%d: ", f, l);
14         va_start(ap, fmt);
15         vprintf(fmt, ap);
16         va_end(ap);
17 }
18
19 #define F(n) {#n, n}
20
21 static struct {
22         char *name;
23         int i;
24 } te[] = {
25 #ifdef FE_DIVBYZERO
26         F(FE_DIVBYZERO),
27 #endif
28 #ifdef FE_INEXACT
29         F(FE_INEXACT),
30 #endif
31 #ifdef FE_INVALID
32         F(FE_INVALID),
33 #endif
34 #ifdef FE_OVERFLOW
35         F(FE_OVERFLOW),
36 #endif
37 #ifdef FE_UNDERFLOW
38         F(FE_UNDERFLOW),
39 #endif
40         {0, 0}
41 };
42
43 static void test_except()
44 {
45         #pragma STDC FENV_ACCESS ON
46         int i,r;
47         fenv_t env;
48
49         for (i=0; te[i].i; i++) {
50                 feclearexcept(FE_ALL_EXCEPT);
51
52                 r = feraiseexcept(te[i].i);
53                 if (r)
54                         error("feraiseexcept(%s) returned %d\n", te[i].name, r);
55                 r = fetestexcept(FE_ALL_EXCEPT);
56                 if (r != te[i].i)
57                         error("feraiseexcept(%s) want %d got %d\n",
58                                 te[i].name, te[i].i, r);
59         }
60
61         r = feraiseexcept(FE_ALL_EXCEPT);
62         if (r != 0)
63                 error("feraisexcept(FE_ALL_EXCEPT) failed\n");
64         r = fegetenv(&env);
65         if (r != 0)
66                 error("fegetenv(&env) = %d\n", r);
67         r = fetestexcept(FE_ALL_EXCEPT);
68         if (r != FE_ALL_EXCEPT)
69                 error("fetestexcept failed: got 0x%x, want 0x%x (FE_ALL_ECXEPT)\n", r, FE_ALL_EXCEPT);
70         r = fesetenv(FE_DFL_ENV);
71         if (r != 0)
72                 error("fesetenv(FE_DFL_ENV) = %d\n", r);
73         r = fetestexcept(FE_ALL_EXCEPT);
74         if (r != 0)
75                 error("fesetenv(FE_DFL_ENV) did not clear exceptions: 0x%x\n", r);
76         r = fesetenv(&env);
77         if (r != 0)
78                 error("fesetenv(&env) = %d\n", r);
79         r = fetestexcept(FE_ALL_EXCEPT);
80         if (r != FE_ALL_EXCEPT)
81                 error("fesetenv(&env) did not restore exceptions: 0x%x\n", r);
82 }
83
84 static struct {
85         char *name;
86         int i;
87 } tr[] = {
88         F(FE_TONEAREST),
89 #ifdef FE_UPWARD
90         F(FE_UPWARD),
91 #endif
92 #ifdef FE_DOWNWARD
93         F(FE_DOWNWARD),
94 #endif
95 #ifdef FE_TOWARDZERO
96         F(FE_TOWARDZERO),
97 #endif
98 };
99
100 static void test_round()
101 {
102         #pragma STDC FENV_ACCESS ON
103         int i,r;
104         fenv_t env;
105         volatile float two100 = 0x1p100;
106         volatile float x;
107
108         for (i=0; i < sizeof tr/sizeof*tr; i++) {
109                 if (tr[i].i < 0)
110                         error("%s (%d) < 0\n", tr[i].name, tr[i].i);
111                 for (r=0; r < i; r++)
112                         if (tr[r].i == tr[i].i)
113                                 error("%s (%d) == %s (%d)\n",
114                                         tr[r].name, tr[r].i, tr[i].name, tr[i].i);
115         }
116
117         for (i=0; i < sizeof tr/sizeof*tr; i++) {
118                 r = fesetround(tr[i].i);
119                 if (r != 0)
120                         error("fesetround(%s) = %d\n", tr[i].name, r);
121                 r = fegetround();
122                 if (r != tr[i].i)
123                         error("fegetround() = 0x%x, wanted 0x%x (%s)\n", r, tr[i].i, tr[i].name);
124         }
125
126 #ifdef FE_UPWARD
127         r = fesetround(FE_UPWARD);
128         if (r != 0)
129                 error("fesetround(FE_UPWARD) failed\n");
130 #endif
131         r = fegetenv(&env);
132         if (r != 0)
133                 error("fegetenv(&env) = %d\n", r);
134         i = fegetround();
135         r = fesetenv(FE_DFL_ENV);
136         if (r != 0)
137                 error("fesetenv(FE_DFL_ENV) = %d\n", r);
138         r = fegetround();
139         if (r != FE_TONEAREST)
140                 error("fesetenv(FE_DFL_ENV) did not set FE_TONEAREST (0x%x), got 0x%x\n", FE_TONEAREST, r);
141         x = two100 + 1;
142         if (x != two100)
143                 error("fesetenv(FE_DFL_ENV) did not set FE_TONEAREST, arithmetics rounds upward\n");
144         x = two100 - 1;
145         if (x != two100)
146                 error("fesetenv(FE_DFL_ENV) did not set FE_TONEAREST, arithmetics rounds downward or tozero\n");
147         r = fesetenv(&env);
148         if (r != 0)
149                 error("fesetenv(&env) = %d\n", r);
150         r = fegetround();
151         if (r != i)
152                 error("fesetenv(&env) did not restore 0x%x, got 0x%x\n", i, r);
153 #ifdef FE_UPWARD
154         x = two100 + 1;
155         if (x == two100)
156                 error("fesetenv did not restore upward rounding\n");
157 #endif
158
159 }
160
161 /* ieee double precision add operation */
162 static struct dd_d t[] = {
163 T(RN,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
164 T(RN,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
165 T(RN,                  0x1p+0,              0x1.01p-53,    0x1.0000000000001p+0,       0x1.fep-2, INEXACT)
166 T(RN,                  0x1p+0,                -0x1p-54,                  0x1p+0,          0x1p-2, INEXACT)
167 T(RN,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
168 T(RN,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
169 T(RN,                 -0x1p+0,             -0x1.01p-53,   -0x1.0000000000001p+0,      -0x1.fep-2, INEXACT)
170 T(RN,                 -0x1p+0,                 0x1p-54,                 -0x1p+0,         -0x1p-2, INEXACT)
171 T(RN,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
172
173 T(RU,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
174 T(RU,                  0x1p+0,                 0x1p-53,    0x1.0000000000001p+0,          0x1p-1, INEXACT)
175 T(RU,                  0x1p+0,              0x1.01p-53,    0x1.0000000000001p+0,       0x1.fep-2, INEXACT)
176 T(RU,                  0x1p+0,                -0x1p-54,                  0x1p+0,          0x1p-2, INEXACT)
177 T(RU,                  0x1p+0,             -0x1.01p-54,                  0x1p+0,       0x1.01p-2, INEXACT)
178 T(RU,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
179 T(RU,                 -0x1p+0,             -0x1.01p-53,                 -0x1p+0,       0x1.01p-1, INEXACT)
180 T(RU,                 -0x1p+0,                 0x1p-54,   -0x1.fffffffffffffp-1,          0x1p-1, INEXACT)
181 T(RU,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
182
183 T(RD,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
184 T(RD,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
185 T(RD,                  0x1p+0,              0x1.01p-53,                  0x1p+0,      -0x1.01p-1, INEXACT)
186 T(RD,                  0x1p+0,                -0x1p-54,    0x1.fffffffffffffp-1,         -0x1p-1, INEXACT)
187 T(RD,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
188 T(RD,                 -0x1p+0,                -0x1p-53,   -0x1.0000000000001p+0,         -0x1p-1, INEXACT)
189 T(RD,                 -0x1p+0,             -0x1.01p-53,   -0x1.0000000000001p+0,      -0x1.fep-2, INEXACT)
190 T(RD,                 -0x1p+0,                 0x1p-54,                 -0x1p+0,         -0x1p-2, INEXACT)
191 T(RD,                 -0x1p+0,              0x1.01p-54,                 -0x1p+0,      -0x1.01p-2, INEXACT)
192
193 T(RZ,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
194 T(RZ,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
195 T(RZ,                  0x1p+0,              0x1.01p-53,                  0x1p+0,      -0x1.01p-1, INEXACT)
196 T(RZ,                  0x1p+0,                -0x1p-54,    0x1.fffffffffffffp-1,         -0x1p-1, INEXACT)
197 T(RZ,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
198 T(RZ,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
199 T(RZ,                 -0x1p+0,             -0x1.01p-53,                 -0x1p+0,       0x1.01p-1, INEXACT)
200 T(RZ,                 -0x1p+0,                 0x1p-54,   -0x1.fffffffffffffp-1,          0x1p-1, INEXACT)
201 T(RZ,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
202 };
203
204 static void test_round_add(void)
205 {
206         #pragma STDC FENV_ACCESS ON
207         double y;
208         float d;
209         int i;
210         struct dd_d *p;
211
212         for (i = 0; i < sizeof t/sizeof *t; i++) {
213                 p = t + i;
214
215                 if (p->r < 0)
216                         continue;
217                 fesetround(p->r);
218                 y = p->x + p->x2;
219                 d = ulperr(y, p->y, p->dy);
220                 if (!checkcr(y, p->y, p->r)) {
221                         printf("%s:%d: %s %a+%a want %a got %a ulperr %.3f = %a + %a\n",
222                                 p->file, p->line, rstr(p->r), p->x, p->x2, p->y, y, d, d-p->dy, p->dy);
223                         test_status = 1;
224                 }
225         }
226 }
227
228 static void test_bad(void)
229 {
230         fexcept_t f;
231         int r;
232
233         r = feclearexcept(FE_ALL_EXCEPT);
234         if (r != 0)
235                 error("feclearexcept(FE_ALL_EXCEPT) failed\n");
236         r = fetestexcept(-1);
237         if (r != 0)
238                 error("fetestexcept(-1) should return 0 when all exceptions are cleared, got %d\n", r);
239         r = feraiseexcept(1234567|FE_ALL_EXCEPT);
240         if (r != 0)
241                 error("feraiseexcept returned non-zero for non-supported exceptions: %d\n", r);
242         r = feclearexcept(1234567|FE_ALL_EXCEPT);
243         if (r != 0)
244                 error("feclearexcept returned non-zero for non-supported exceptions: %d\n", r);
245         r = fesetround(1234567);
246         if (r == 0)
247                 error("fesetround should fail on invalid rounding mode\n");
248         r = fegetexceptflag(&f, 1234567);
249         if (r != 0)
250                 error("fegetexceptflag returned non-zero for non-supported exceptions: %d\n", r);
251         r = fegetexceptflag(&f, 0);
252         if (r != 0)
253                 error("fegetexceptflag(0) failed\n");
254         r = fesetexceptflag(&f, 1234567);
255         if (r != 0)
256                 error("fesetexceptflag returned non-zero fir non-supported exceptions: %d\n", r);
257 }
258
259 int main(void)
260 {
261         test_except();
262         test_round();
263         test_round_add();
264         test_bad();
265         return test_status;
266 }