test fenv functions with bad arguments
[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
106         for (i=0; i < sizeof tr/sizeof*tr; i++) {
107                 if (tr[i].i < 0)
108                         error("%s (%d) < 0\n", tr[i].name, tr[i].i);
109                 for (r=0; r < i; r++)
110                         if (tr[r].i == tr[i].i)
111                                 error("%s (%d) == %s (%d)\n",
112                                         tr[r].name, tr[r].i, tr[i].name, tr[i].i);
113         }
114
115         for (i=0; i < sizeof tr/sizeof*tr; i++) {
116                 r = fesetround(tr[i].i);
117                 if (r != 0)
118                         error("fesetround(%s) = %d\n", tr[i].name, r);
119                 r = fegetround();
120                 if (r != tr[i].i)
121                         error("fegetround() = 0x%x, wanted 0x%x (%s)\n", r, tr[i].i, tr[i].name);
122         }
123
124         r = fegetenv(&env);
125         if (r != 0)
126                 error("fegetenv(&env) = %d\n", r);
127         i = fegetround();
128         r = fesetenv(FE_DFL_ENV);
129         if (r != 0)
130                 error("fesetenv(FE_DFL_ENV) = %d\n", r);
131         r = fegetround();
132         if (r != FE_TONEAREST)
133                 error("fesetenv(FE_DFL_ENV) did not set FE_TONEAREST (0x%x), got 0x%x\n", FE_TONEAREST, r);
134         r = fesetenv(&env);
135         if (r != 0)
136                 error("fesetenv(&env) = %d\n", r);
137         r = fegetround();
138         if (r != i)
139                 error("fesetenv(&env) did not restore 0x%x, got 0x%x\n", i, r);
140 }
141
142 /* ieee double precision add operation */
143 static struct dd_d t[] = {
144 T(RN,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
145 T(RN,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
146 T(RN,                  0x1p+0,              0x1.01p-53,    0x1.0000000000001p+0,       0x1.fep-2, INEXACT)
147 T(RN,                  0x1p+0,                -0x1p-54,                  0x1p+0,          0x1p-2, INEXACT)
148 T(RN,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
149 T(RN,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
150 T(RN,                 -0x1p+0,             -0x1.01p-53,   -0x1.0000000000001p+0,      -0x1.fep-2, INEXACT)
151 T(RN,                 -0x1p+0,                 0x1p-54,                 -0x1p+0,         -0x1p-2, INEXACT)
152 T(RN,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
153
154 T(RU,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
155 T(RU,                  0x1p+0,                 0x1p-53,    0x1.0000000000001p+0,          0x1p-1, INEXACT)
156 T(RU,                  0x1p+0,              0x1.01p-53,    0x1.0000000000001p+0,       0x1.fep-2, INEXACT)
157 T(RU,                  0x1p+0,                -0x1p-54,                  0x1p+0,          0x1p-2, INEXACT)
158 T(RU,                  0x1p+0,             -0x1.01p-54,                  0x1p+0,       0x1.01p-2, INEXACT)
159 T(RU,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
160 T(RU,                 -0x1p+0,             -0x1.01p-53,                 -0x1p+0,       0x1.01p-1, INEXACT)
161 T(RU,                 -0x1p+0,                 0x1p-54,   -0x1.fffffffffffffp-1,          0x1p-1, INEXACT)
162 T(RU,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
163
164 T(RD,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
165 T(RD,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
166 T(RD,                  0x1p+0,              0x1.01p-53,                  0x1p+0,      -0x1.01p-1, INEXACT)
167 T(RD,                  0x1p+0,                -0x1p-54,    0x1.fffffffffffffp-1,         -0x1p-1, INEXACT)
168 T(RD,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
169 T(RD,                 -0x1p+0,                -0x1p-53,   -0x1.0000000000001p+0,         -0x1p-1, INEXACT)
170 T(RD,                 -0x1p+0,             -0x1.01p-53,   -0x1.0000000000001p+0,      -0x1.fep-2, INEXACT)
171 T(RD,                 -0x1p+0,                 0x1p-54,                 -0x1p+0,         -0x1p-2, INEXACT)
172 T(RD,                 -0x1p+0,              0x1.01p-54,                 -0x1p+0,      -0x1.01p-2, INEXACT)
173
174 T(RZ,                  0x1p+0,                 0x1p-52,    0x1.0000000000001p+0,          0x0p+0, 0)
175 T(RZ,                  0x1p+0,                 0x1p-53,                  0x1p+0,         -0x1p-1, INEXACT)
176 T(RZ,                  0x1p+0,              0x1.01p-53,                  0x1p+0,      -0x1.01p-1, INEXACT)
177 T(RZ,                  0x1p+0,                -0x1p-54,    0x1.fffffffffffffp-1,         -0x1p-1, INEXACT)
178 T(RZ,                  0x1p+0,             -0x1.01p-54,    0x1.fffffffffffffp-1,      -0x1.fep-2, INEXACT)
179 T(RZ,                 -0x1p+0,                -0x1p-53,                 -0x1p+0,          0x1p-1, INEXACT)
180 T(RZ,                 -0x1p+0,             -0x1.01p-53,                 -0x1p+0,       0x1.01p-1, INEXACT)
181 T(RZ,                 -0x1p+0,                 0x1p-54,   -0x1.fffffffffffffp-1,          0x1p-1, INEXACT)
182 T(RZ,                 -0x1p+0,              0x1.01p-54,   -0x1.fffffffffffffp-1,       0x1.fep-2, INEXACT)
183 };
184
185 static void test_round_add(void)
186 {
187         #pragma STDC FENV_ACCESS ON
188         double y;
189         float d;
190         int i;
191         struct dd_d *p;
192
193         for (i = 0; i < sizeof t/sizeof *t; i++) {
194                 p = t + i;
195
196                 if (p->r < 0)
197                         continue;
198                 fesetround(p->r);
199                 y = p->x + p->x2;
200                 d = ulperr(y, p->y, p->dy);
201                 if (!checkcr(y, p->y, p->r)) {
202                         printf("%s:%d: %s %a+%a want %a got %a ulperr %.3f = %a + %a\n",
203                                 p->file, p->line, rstr(p->r), p->x, p->x2, p->y, y, d, d-p->dy, p->dy);
204                         test_status = 1;
205                 }
206         }
207 }
208
209 static void test_bad(void)
210 {
211         fexcept_t f;
212         int r;
213
214         r = fetestexcept(1234567);
215         if (r == 0)
216                 error("fetestexcept should return non-zero on non-supported exceptions\n");
217         r = feraiseexcept(1234567);
218         if (r == 0)
219                 error("feraiseexcept should return non-zero on non-supported exceptions\n");
220         r = feclearexcept(1234567);
221         if (r == 0)
222                 error("feclearexcept should return non-zero on non-supported exceptions\n");
223         r = fesetround(1234567);
224         if (r == 0)
225                 error("fesetround should fail on invalid rounding mode\n");
226         r = fegetexceptflag(&f, 1234567);
227         if (r == 0)
228                 error("fegetexceptflag should return non-zero on non-supported exceptions\n");
229         r = fegetexceptflag(&f, 0);
230         if (r != 0)
231                 error("fegetexceptflag(0) failed\n");
232         r = fesetexceptflag(&f, 1234567);
233         if (r == 0)
234                 error("fesetexceptflag should return non-zero on non-supported exceptions\n");
235 }
236
237 int main(void)
238 {
239         test_except();
240         test_round();
241         test_round_add();
242         test_bad();
243         return test_status;
244 }