]>
Commit | Line | Data |
---|---|---|
85b29045 | 1 | /* Test for fenv inline implementations. |
688903eb | 2 | Copyright (C) 2015-2018 Free Software Foundation, Inc. |
85b29045 AZ |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #ifndef _GNU_SOURCE | |
20 | # define _GNU_SOURCE | |
21 | #endif | |
22 | ||
23 | /* To make sure the fenv inline function are used. */ | |
24 | #undef __NO_MATH_INLINES | |
25 | ||
26 | #include <fenv.h> | |
27 | #include <stdio.h> | |
28 | #include <math-tests.h> | |
29 | ||
30 | /* | |
31 | Since not all architectures might define all exceptions, we define | |
32 | a private set and map accordingly. | |
33 | */ | |
34 | #define NO_EXC 0 | |
35 | #define INEXACT_EXC 0x1 | |
36 | #define DIVBYZERO_EXC 0x2 | |
37 | #define UNDERFLOW_EXC 0x04 | |
38 | #define OVERFLOW_EXC 0x08 | |
39 | #define INVALID_EXC 0x10 | |
40 | #define ALL_EXC \ | |
41 | (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC | \ | |
42 | INVALID_EXC) | |
43 | static int count_errors; | |
44 | ||
45 | #if FE_ALL_EXCEPT | |
46 | static void | |
47 | test_single_exception_fp_int (int exception, | |
48 | int exc_flag, | |
49 | int fe_flag, | |
50 | const char *flag_name) | |
51 | { | |
52 | if (exception & exc_flag) | |
53 | { | |
54 | if (fetestexcept (fe_flag)) | |
55 | printf (" Pass: Exception \"%s\" is set\n", flag_name); | |
56 | else | |
57 | { | |
58 | printf (" Fail: Exception \"%s\" is not set\n", flag_name); | |
59 | ++count_errors; | |
60 | } | |
61 | } | |
62 | else | |
63 | { | |
64 | if (fetestexcept (fe_flag)) | |
65 | { | |
66 | printf (" Fail: Exception \"%s\" is set\n", flag_name); | |
67 | ++count_errors; | |
68 | } | |
69 | else | |
70 | printf (" Pass: Exception \"%s\" is not set\n", flag_name); | |
71 | } | |
72 | } | |
73 | /* Test whether a given exception was raised. */ | |
74 | static void | |
75 | test_single_exception_fp_double (int exception, | |
76 | int exc_flag, | |
77 | double fe_flag, | |
78 | const char *flag_name) | |
79 | { | |
80 | if (exception & exc_flag) | |
81 | { | |
82 | if (fetestexcept (fe_flag)) | |
83 | printf (" Pass: Exception \"%s\" is set\n", flag_name); | |
84 | else | |
85 | { | |
86 | printf (" Fail: Exception \"%s\" is not set\n", flag_name); | |
87 | ++count_errors; | |
88 | } | |
89 | } | |
90 | else | |
91 | { | |
92 | if (fetestexcept (fe_flag)) | |
93 | { | |
94 | printf (" Fail: Exception \"%s\" is set\n", flag_name); | |
95 | ++count_errors; | |
96 | } | |
97 | else | |
98 | printf (" Pass: Exception \"%s\" is not set\n", flag_name); | |
99 | } | |
100 | } | |
101 | #endif | |
102 | ||
103 | static void | |
104 | test_exceptions (const char *test_name, int exception) | |
105 | { | |
106 | printf ("Test: %s\n", test_name); | |
107 | #ifdef FE_DIVBYZERO | |
108 | test_single_exception_fp_double (exception, DIVBYZERO_EXC, FE_DIVBYZERO, | |
109 | "DIVBYZERO"); | |
110 | #endif | |
111 | #ifdef FE_INVALID | |
112 | test_single_exception_fp_double (exception, INVALID_EXC, FE_INVALID, | |
113 | "INVALID"); | |
114 | #endif | |
115 | #ifdef FE_INEXACT | |
116 | test_single_exception_fp_double (exception, INEXACT_EXC, FE_INEXACT, | |
117 | "INEXACT"); | |
118 | #endif | |
119 | #ifdef FE_UNDERFLOW | |
120 | test_single_exception_fp_double (exception, UNDERFLOW_EXC, FE_UNDERFLOW, | |
121 | "UNDERFLOW"); | |
122 | #endif | |
123 | #ifdef FE_OVERFLOW | |
124 | test_single_exception_fp_double (exception, OVERFLOW_EXC, FE_OVERFLOW, | |
125 | "OVERFLOW"); | |
126 | #endif | |
127 | } | |
128 | ||
129 | static void | |
130 | test_exceptionflag (void) | |
131 | { | |
132 | printf ("Test: fegetexceptionflag (FE_ALL_EXCEPT)\n"); | |
133 | #if FE_ALL_EXCEPT | |
134 | fexcept_t excepts; | |
135 | ||
136 | feclearexcept (FE_ALL_EXCEPT); | |
137 | ||
138 | feraiseexcept (FE_INVALID); | |
139 | fegetexceptflag (&excepts, FE_ALL_EXCEPT); | |
140 | ||
141 | feclearexcept (FE_ALL_EXCEPT); | |
142 | feraiseexcept (FE_OVERFLOW | FE_INEXACT); | |
143 | ||
144 | fesetexceptflag (&excepts, FE_ALL_EXCEPT); | |
145 | ||
146 | test_single_exception_fp_int (INVALID_EXC, INVALID_EXC, FE_INVALID, | |
147 | "INVALID (int)"); | |
148 | test_single_exception_fp_int (INVALID_EXC, OVERFLOW_EXC, FE_OVERFLOW, | |
149 | "OVERFLOW (int)"); | |
150 | test_single_exception_fp_int (INVALID_EXC, INEXACT_EXC, FE_INEXACT, | |
151 | "INEXACT (int)"); | |
152 | ||
153 | /* Same test, but using double as argument */ | |
154 | feclearexcept (FE_ALL_EXCEPT); | |
155 | ||
156 | feraiseexcept (FE_INVALID); | |
157 | fegetexceptflag (&excepts, (double)FE_ALL_EXCEPT); | |
158 | ||
159 | feclearexcept (FE_ALL_EXCEPT); | |
160 | feraiseexcept (FE_OVERFLOW | FE_INEXACT); | |
161 | ||
162 | fesetexceptflag (&excepts, (double)FE_ALL_EXCEPT); | |
163 | ||
164 | test_single_exception_fp_double (INVALID_EXC, INVALID_EXC, FE_INVALID, | |
165 | "INVALID (double)"); | |
166 | test_single_exception_fp_double (INVALID_EXC, OVERFLOW_EXC, FE_OVERFLOW, | |
167 | "OVERFLOW (double)"); | |
168 | test_single_exception_fp_double (INVALID_EXC, INEXACT_EXC, FE_INEXACT, | |
169 | "INEXACT (double)"); | |
170 | #endif | |
171 | } | |
172 | ||
173 | static void | |
174 | test_fesetround (void) | |
175 | { | |
176 | #if defined FE_TONEAREST && defined FE_TOWARDZERO | |
177 | int res1; | |
178 | int res2; | |
179 | ||
180 | printf ("Tests for fesetround\n"); | |
181 | ||
182 | /* The fesetround should not itself cause the test to fail, however it | |
183 | should either succeed for both 'int' and 'double' argument, or fail | |
184 | for both. */ | |
185 | res1 = fesetround ((int) FE_TOWARDZERO); | |
186 | res2 = fesetround ((double) FE_TOWARDZERO); | |
187 | if (res1 != res2) | |
188 | { | |
189 | printf ("fesetround (FE_TOWARDZERO) failed: %d, %d\n", res1, res2); | |
190 | ++count_errors; | |
191 | } | |
192 | ||
193 | res1 = fesetround ((int) FE_TONEAREST); | |
194 | res2 = fesetround ((double) FE_TONEAREST); | |
195 | if (res1 != res2) | |
196 | { | |
197 | printf ("fesetround (FE_TONEAREST) failed: %d, %d\n", res1, res2); | |
198 | ++count_errors; | |
199 | } | |
200 | #endif | |
201 | } | |
202 | ||
75413d49 | 203 | #if FE_ALL_EXCEPT |
85b29045 AZ |
204 | /* Tests for feenableexcept/fedisableexcept. */ |
205 | static void | |
206 | feenable_test (const char *flag_name, fexcept_t fe_exc) | |
207 | { | |
85b29045 AZ |
208 | int fe_exci = fe_exc; |
209 | double fe_excd = fe_exc; | |
210 | int excepts; | |
211 | ||
212 | /* First disable all exceptions. */ | |
213 | if (fedisableexcept (FE_ALL_EXCEPT) == -1) | |
214 | { | |
215 | printf ("Test: fedisableexcept (FE_ALL_EXCEPT) failed\n"); | |
216 | ++count_errors; | |
217 | /* If this fails, the other tests don't make sense. */ | |
218 | return; | |
219 | } | |
220 | ||
221 | /* Test for inline macros using integer argument. */ | |
222 | excepts = feenableexcept (fe_exci); | |
223 | if (!EXCEPTION_ENABLE_SUPPORTED (fe_exci) && excepts == -1) | |
224 | { | |
225 | printf ("Test: not testing feenableexcept, it isn't implemented.\n"); | |
226 | return; | |
227 | } | |
228 | if (excepts == -1) | |
229 | { | |
230 | printf ("Test: feenableexcept (%s) failed\n", flag_name); | |
231 | ++count_errors; | |
232 | return; | |
233 | } | |
234 | if (excepts != 0) | |
235 | { | |
236 | printf ("Test: feenableexcept (%s) failed, return should be 0, is %x\n", | |
237 | flag_name, excepts); | |
238 | ++count_errors; | |
239 | } | |
240 | ||
241 | /* And now disable the exception again. */ | |
242 | excepts = fedisableexcept (fe_exc); | |
243 | if (excepts == -1) | |
244 | { | |
245 | printf ("Test: fedisableexcept (%s) failed\n", flag_name); | |
246 | ++count_errors; | |
247 | return; | |
248 | } | |
249 | if (excepts != fe_exc) | |
250 | { | |
251 | printf ("Test: fedisableexcept (%s) failed, return should be 0x%x, is 0x%x\n", | |
9e8c0381 | 252 | flag_name, (unsigned int)fe_exc, excepts); |
85b29045 AZ |
253 | ++count_errors; |
254 | } | |
255 | ||
256 | /* Test for inline macros using double argument. */ | |
257 | excepts = feenableexcept (fe_excd); | |
258 | if (!EXCEPTION_ENABLE_SUPPORTED (fe_excd) && excepts == -1) | |
259 | { | |
260 | printf ("Test: not testing feenableexcept, it isn't implemented.\n"); | |
261 | return; | |
262 | } | |
263 | if (excepts == -1) | |
264 | { | |
265 | printf ("Test: feenableexcept (%s) failed\n", flag_name); | |
266 | ++count_errors; | |
267 | return; | |
268 | } | |
269 | if (excepts != 0) | |
270 | { | |
271 | printf ("Test: feenableexcept (%s) failed, return should be 0, is %x\n", | |
272 | flag_name, excepts); | |
273 | ++count_errors; | |
274 | } | |
275 | ||
276 | /* And now disable the exception again. */ | |
277 | excepts = fedisableexcept (fe_exc); | |
278 | if (excepts == -1) | |
279 | { | |
280 | printf ("Test: fedisableexcept (%s) failed\n", flag_name); | |
281 | ++count_errors; | |
282 | return; | |
283 | } | |
284 | if (excepts != fe_exc) | |
285 | { | |
286 | printf ("Test: fedisableexcept (%s) failed, return should be 0x%x, is 0x%x\n", | |
9e8c0381 | 287 | flag_name, (unsigned int)fe_exc, excepts); |
85b29045 AZ |
288 | ++count_errors; |
289 | } | |
85b29045 | 290 | } |
75413d49 | 291 | #endif |
85b29045 AZ |
292 | |
293 | static void | |
294 | test_feenabledisable (void) | |
295 | { | |
296 | printf ("Tests for feenableexcepts/fedisableexcept\n"); | |
297 | ||
298 | /* We might have some exceptions still set. */ | |
299 | feclearexcept (FE_ALL_EXCEPT); | |
300 | ||
301 | #ifdef FE_DIVBYZERO | |
302 | feenable_test ("FE_DIVBYZERO", FE_DIVBYZERO); | |
303 | #endif | |
304 | #ifdef FE_INVALID | |
305 | feenable_test ("FE_INVALID", FE_INVALID); | |
306 | #endif | |
307 | #ifdef FE_INEXACT | |
308 | feenable_test ("FE_INEXACT", FE_INEXACT); | |
309 | #endif | |
310 | #ifdef FE_UNDERFLOW | |
311 | feenable_test ("FE_UNDERFLOW", FE_UNDERFLOW); | |
312 | #endif | |
313 | #ifdef FE_OVERFLOW | |
314 | feenable_test ("FE_OVERFLOW", FE_OVERFLOW); | |
315 | #endif | |
316 | fesetenv (FE_DFL_ENV); | |
317 | } | |
318 | ||
319 | static int | |
320 | do_test (void) | |
321 | { | |
322 | /* clear all exceptions and test if all are cleared */ | |
323 | feclearexcept (FE_ALL_EXCEPT); | |
324 | test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions", | |
325 | NO_EXC); | |
326 | ||
327 | /* raise all exceptions and test if all are raised */ | |
328 | feraiseexcept (FE_ALL_EXCEPT); | |
daaff5cc JM |
329 | if (EXCEPTION_TESTS (float)) |
330 | test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions", | |
331 | ALL_EXC); | |
85b29045 AZ |
332 | |
333 | /* Same test, but using double as argument */ | |
334 | feclearexcept ((double)FE_ALL_EXCEPT); | |
335 | test_exceptions ("feclearexcept ((double)FE_ALL_EXCEPT) clears all exceptions", | |
336 | NO_EXC); | |
337 | ||
338 | feraiseexcept ((double)FE_ALL_EXCEPT); | |
daaff5cc JM |
339 | if (EXCEPTION_TESTS (float)) |
340 | test_exceptions ("feraiseexcept ((double)FE_ALL_EXCEPT) raises all exceptions", | |
341 | ALL_EXC); | |
85b29045 | 342 | |
daaff5cc JM |
343 | if (EXCEPTION_TESTS (float)) |
344 | test_exceptionflag (); | |
85b29045 AZ |
345 | |
346 | test_fesetround (); | |
347 | ||
348 | test_feenabledisable (); | |
349 | ||
350 | return count_errors; | |
351 | } | |
352 | ||
353 | #define TEST_FUNCTION do_test () | |
354 | #include "../test-skeleton.c" |