1 | /* Copyright (C) 1997-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* Tests for ISO C99 7.6: Floating-point environment */ |
19 | |
20 | #ifndef _GNU_SOURCE |
21 | # define _GNU_SOURCE |
22 | #endif |
23 | |
24 | #include <complex.h> |
25 | #include <math.h> |
26 | #include <float.h> |
27 | #include <fenv.h> |
28 | |
29 | #include <errno.h> |
30 | #include <signal.h> |
31 | #include <stdlib.h> |
32 | #include <stdio.h> |
33 | #include <string.h> |
34 | #include <unistd.h> |
35 | #include <sys/wait.h> |
36 | #include <sys/resource.h> |
37 | #include <math-tests.h> |
38 | |
39 | /* |
40 | Since not all architectures might define all exceptions, we define |
41 | a private set and map accordingly. |
42 | */ |
43 | #define NO_EXC 0 |
44 | #define INEXACT_EXC 0x1 |
45 | #define DIVBYZERO_EXC 0x2 |
46 | #define UNDERFLOW_EXC 0x04 |
47 | #define OVERFLOW_EXC 0x08 |
48 | #define INVALID_EXC 0x10 |
49 | #define ALL_EXC \ |
50 | (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC \ |
51 | | INVALID_EXC) |
52 | |
53 | static int count_errors; |
54 | |
55 | #if FE_ALL_EXCEPT |
56 | /* Test whether a given exception was raised. */ |
57 | static void |
58 | test_single_exception (short int exception, |
59 | short int exc_flag, |
60 | fexcept_t fe_flag, |
61 | const char *flag_name) |
62 | { |
63 | if (exception & exc_flag) |
64 | { |
65 | if (fetestexcept (excepts: fe_flag)) |
66 | printf (format: " Pass: Exception \"%s\" is set\n" , flag_name); |
67 | else |
68 | { |
69 | printf (format: " Fail: Exception \"%s\" is not set\n" , flag_name); |
70 | ++count_errors; |
71 | } |
72 | } |
73 | else |
74 | { |
75 | if (fetestexcept (excepts: fe_flag)) |
76 | { |
77 | printf (format: " Fail: Exception \"%s\" is set\n" , flag_name); |
78 | ++count_errors; |
79 | } |
80 | else |
81 | { |
82 | printf (format: " Pass: Exception \"%s\" is not set\n" , flag_name); |
83 | } |
84 | } |
85 | } |
86 | #endif |
87 | |
88 | static void |
89 | test_exceptions (const char *test_name, short int exception, |
90 | int ignore_inexact) |
91 | { |
92 | printf (format: "Test: %s\n" , test_name); |
93 | #ifdef FE_DIVBYZERO |
94 | test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO, |
95 | flag_name: "DIVBYZERO" ); |
96 | #endif |
97 | #ifdef FE_INVALID |
98 | test_single_exception (exception, INVALID_EXC, FE_INVALID, |
99 | flag_name: "INVALID" ); |
100 | #endif |
101 | #ifdef FE_INEXACT |
102 | if (!ignore_inexact) |
103 | test_single_exception (exception, INEXACT_EXC, FE_INEXACT, |
104 | flag_name: "INEXACT" ); |
105 | #endif |
106 | #ifdef FE_UNDERFLOW |
107 | test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW, |
108 | flag_name: "UNDERFLOW" ); |
109 | #endif |
110 | #ifdef FE_OVERFLOW |
111 | test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW, |
112 | flag_name: "OVERFLOW" ); |
113 | #endif |
114 | } |
115 | |
116 | static void |
117 | print_rounding (int rounding) |
118 | { |
119 | |
120 | switch (rounding) |
121 | { |
122 | #ifdef FE_TONEAREST |
123 | case FE_TONEAREST: |
124 | printf (format: "TONEAREST" ); |
125 | break; |
126 | #endif |
127 | #ifdef FE_UPWARD |
128 | case FE_UPWARD: |
129 | printf (format: "UPWARD" ); |
130 | break; |
131 | #endif |
132 | #ifdef FE_DOWNWARD |
133 | case FE_DOWNWARD: |
134 | printf (format: "DOWNWARD" ); |
135 | break; |
136 | #endif |
137 | #ifdef FE_TOWARDZERO |
138 | case FE_TOWARDZERO: |
139 | printf (format: "TOWARDZERO" ); |
140 | break; |
141 | #endif |
142 | } |
143 | printf (format: ".\n" ); |
144 | } |
145 | |
146 | |
147 | static void |
148 | test_rounding (const char *test_name, int rounding_mode) |
149 | { |
150 | int curr_rounding = fegetround (); |
151 | |
152 | printf (format: "Test: %s\n" , test_name); |
153 | if (curr_rounding == rounding_mode) |
154 | { |
155 | printf (format: " Pass: Rounding mode is " ); |
156 | print_rounding (rounding: curr_rounding); |
157 | } |
158 | else |
159 | { |
160 | ++count_errors; |
161 | printf (format: " Fail: Rounding mode is " ); |
162 | print_rounding (rounding: curr_rounding); |
163 | } |
164 | } |
165 | |
166 | |
167 | #if FE_ALL_EXCEPT |
168 | static void |
169 | set_single_exc (const char *test_name, int fe_exc, fexcept_t exception) |
170 | { |
171 | char str[200]; |
172 | /* The standard allows the inexact exception to be set together with the |
173 | underflow and overflow exceptions. So ignore the inexact flag if the |
174 | others are raised. */ |
175 | int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0; |
176 | |
177 | strcpy (dest: str, src: test_name); |
178 | strcat (dest: str, src: ": set flag, with rest not set" ); |
179 | feclearexcept (FE_ALL_EXCEPT); |
180 | feraiseexcept (excepts: exception); |
181 | test_exceptions (test_name: str, exception: fe_exc, ignore_inexact); |
182 | |
183 | strcpy (dest: str, src: test_name); |
184 | strcat (dest: str, src: ": clear flag, rest also unset" ); |
185 | feclearexcept (excepts: exception); |
186 | test_exceptions (test_name: str, NO_EXC, ignore_inexact); |
187 | |
188 | strcpy (dest: str, src: test_name); |
189 | strcat (dest: str, src: ": set flag, with rest set" ); |
190 | feraiseexcept (FE_ALL_EXCEPT ^ exception); |
191 | feraiseexcept (excepts: exception); |
192 | test_exceptions (test_name: str, ALL_EXC, ignore_inexact: 0); |
193 | |
194 | strcpy (dest: str, src: test_name); |
195 | strcat (dest: str, src: ": clear flag, leave rest set" ); |
196 | feclearexcept (excepts: exception); |
197 | test_exceptions (test_name: str, ALL_EXC ^ fe_exc, ignore_inexact: 0); |
198 | } |
199 | #endif |
200 | |
201 | static void |
202 | fe_tests (void) |
203 | { |
204 | /* clear all exceptions and test if all are cleared */ |
205 | feclearexcept (FE_ALL_EXCEPT); |
206 | test_exceptions (test_name: "feclearexcept (FE_ALL_EXCEPT) clears all exceptions" , |
207 | NO_EXC, ignore_inexact: 0); |
208 | |
209 | /* Skip further tests here if exceptions not supported. */ |
210 | if (!EXCEPTION_TESTS (float) && FE_ALL_EXCEPT != 0) |
211 | return; |
212 | /* raise all exceptions and test if all are raised */ |
213 | feraiseexcept (FE_ALL_EXCEPT); |
214 | test_exceptions (test_name: "feraiseexcept (FE_ALL_EXCEPT) raises all exceptions" , |
215 | ALL_EXC, ignore_inexact: 0); |
216 | feclearexcept (FE_ALL_EXCEPT); |
217 | |
218 | #ifdef FE_DIVBYZERO |
219 | set_single_exc (test_name: "Set/Clear FE_DIVBYZERO" , DIVBYZERO_EXC, FE_DIVBYZERO); |
220 | #endif |
221 | #ifdef FE_INVALID |
222 | set_single_exc (test_name: "Set/Clear FE_INVALID" , INVALID_EXC, FE_INVALID); |
223 | #endif |
224 | #ifdef FE_INEXACT |
225 | set_single_exc (test_name: "Set/Clear FE_INEXACT" , INEXACT_EXC, FE_INEXACT); |
226 | #endif |
227 | #ifdef FE_UNDERFLOW |
228 | set_single_exc (test_name: "Set/Clear FE_UNDERFLOW" , UNDERFLOW_EXC, FE_UNDERFLOW); |
229 | #endif |
230 | #ifdef FE_OVERFLOW |
231 | set_single_exc (test_name: "Set/Clear FE_OVERFLOW" , OVERFLOW_EXC, FE_OVERFLOW); |
232 | #endif |
233 | } |
234 | |
235 | #if FE_ALL_EXCEPT |
236 | /* Test that program aborts with no masked interrupts */ |
237 | static void |
238 | feenv_nomask_test (const char *flag_name, int fe_exc) |
239 | { |
240 | # if defined FE_NOMASK_ENV |
241 | int status; |
242 | pid_t pid; |
243 | |
244 | if (!EXCEPTION_ENABLE_SUPPORTED (FE_ALL_EXCEPT) |
245 | && fesetenv (FE_NOMASK_ENV) != 0) |
246 | { |
247 | printf (format: "Test: not testing FE_NOMASK_ENV, it isn't implemented.\n" ); |
248 | return; |
249 | } |
250 | |
251 | printf (format: "Test: after fesetenv (FE_NOMASK_ENV) processes will abort\n" ); |
252 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
253 | pid = fork (); |
254 | if (pid == 0) |
255 | { |
256 | # ifdef RLIMIT_CORE |
257 | /* Try to avoid dumping core. */ |
258 | struct rlimit core_limit; |
259 | core_limit.rlim_cur = 0; |
260 | core_limit.rlim_max = 0; |
261 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
262 | # endif |
263 | |
264 | fesetenv (FE_NOMASK_ENV); |
265 | feraiseexcept (excepts: fe_exc); |
266 | exit (status: 2); |
267 | } |
268 | else if (pid < 0) |
269 | { |
270 | if (errno != ENOSYS) |
271 | { |
272 | printf (format: " Fail: Could not fork.\n" ); |
273 | ++count_errors; |
274 | } |
275 | else |
276 | printf (format: " `fork' not implemented, test ignored.\n" ); |
277 | } |
278 | else { |
279 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
280 | { |
281 | printf (format: " Fail: waitpid call failed.\n" ); |
282 | ++count_errors; |
283 | } |
284 | else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE) |
285 | printf (format: " Pass: Process received SIGFPE.\n" ); |
286 | else |
287 | { |
288 | printf (format: " Fail: Process didn't receive signal and exited with status %d.\n" , |
289 | status); |
290 | ++count_errors; |
291 | } |
292 | } |
293 | # endif |
294 | } |
295 | |
296 | /* Test that program doesn't abort with default environment */ |
297 | static void |
298 | feenv_mask_test (const char *flag_name, int fe_exc) |
299 | { |
300 | int status; |
301 | pid_t pid; |
302 | |
303 | printf (format: "Test: after fesetenv (FE_DFL_ENV) processes will not abort\n" ); |
304 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
305 | pid = fork (); |
306 | if (pid == 0) |
307 | { |
308 | #ifdef RLIMIT_CORE |
309 | /* Try to avoid dumping core. */ |
310 | struct rlimit core_limit; |
311 | core_limit.rlim_cur = 0; |
312 | core_limit.rlim_max = 0; |
313 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
314 | #endif |
315 | |
316 | fesetenv (FE_DFL_ENV); |
317 | feraiseexcept (excepts: fe_exc); |
318 | exit (status: 2); |
319 | } |
320 | else if (pid < 0) |
321 | { |
322 | if (errno != ENOSYS) |
323 | { |
324 | printf (format: " Fail: Could not fork.\n" ); |
325 | ++count_errors; |
326 | } |
327 | else |
328 | printf (format: " `fork' not implemented, test ignored.\n" ); |
329 | } |
330 | else { |
331 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
332 | { |
333 | printf (format: " Fail: waitpid call failed.\n" ); |
334 | ++count_errors; |
335 | } |
336 | else if (WIFEXITED (status) && WEXITSTATUS (status) == 2) |
337 | printf (format: " Pass: Process exited normally.\n" ); |
338 | else |
339 | { |
340 | printf (format: " Fail: Process exited abnormally with status %d.\n" , |
341 | status); |
342 | ++count_errors; |
343 | } |
344 | } |
345 | } |
346 | |
347 | /* Test that program aborts with no masked interrupts */ |
348 | static void |
349 | feexcp_nomask_test (const char *flag_name, int fe_exc) |
350 | { |
351 | int status; |
352 | pid_t pid; |
353 | |
354 | if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && feenableexcept (excepts: fe_exc) == -1) |
355 | { |
356 | printf (format: "Test: not testing feenableexcept, it isn't implemented.\n" ); |
357 | return; |
358 | } |
359 | |
360 | printf (format: "Test: after feenableexcept (%s) processes will abort\n" , |
361 | flag_name); |
362 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
363 | pid = fork (); |
364 | if (pid == 0) |
365 | { |
366 | #ifdef RLIMIT_CORE |
367 | /* Try to avoid dumping core. */ |
368 | struct rlimit core_limit; |
369 | core_limit.rlim_cur = 0; |
370 | core_limit.rlim_max = 0; |
371 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
372 | #endif |
373 | |
374 | fedisableexcept (FE_ALL_EXCEPT); |
375 | feenableexcept (excepts: fe_exc); |
376 | feraiseexcept (excepts: fe_exc); |
377 | exit (status: 2); |
378 | } |
379 | else if (pid < 0) |
380 | { |
381 | if (errno != ENOSYS) |
382 | { |
383 | printf (format: " Fail: Could not fork.\n" ); |
384 | ++count_errors; |
385 | } |
386 | else |
387 | printf (format: " `fork' not implemented, test ignored.\n" ); |
388 | } |
389 | else { |
390 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
391 | { |
392 | printf (format: " Fail: waitpid call failed.\n" ); |
393 | ++count_errors; |
394 | } |
395 | else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE) |
396 | printf (format: " Pass: Process received SIGFPE.\n" ); |
397 | else |
398 | { |
399 | printf (format: " Fail: Process didn't receive signal and exited with status %d.\n" , |
400 | status); |
401 | ++count_errors; |
402 | } |
403 | } |
404 | } |
405 | |
406 | /* Test that program doesn't abort with exception. */ |
407 | static void |
408 | feexcp_mask_test (const char *flag_name, int fe_exc) |
409 | { |
410 | int status; |
411 | int exception; |
412 | pid_t pid; |
413 | |
414 | printf (format: "Test: after fedisableexcept (%s) processes will not abort\n" , |
415 | flag_name); |
416 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
417 | pid = fork (); |
418 | if (pid == 0) |
419 | { |
420 | #ifdef RLIMIT_CORE |
421 | /* Try to avoid dumping core. */ |
422 | struct rlimit core_limit; |
423 | core_limit.rlim_cur = 0; |
424 | core_limit.rlim_max = 0; |
425 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
426 | #endif |
427 | feenableexcept (FE_ALL_EXCEPT); |
428 | exception = fe_exc; |
429 | #ifdef FE_INEXACT |
430 | /* The standard allows the inexact exception to be set together with the |
431 | underflow and overflow exceptions. So add FE_INEXACT to the set of |
432 | exceptions to be disabled if we will be raising underflow or |
433 | overflow. */ |
434 | # ifdef FE_OVERFLOW |
435 | if (fe_exc & FE_OVERFLOW) |
436 | exception |= FE_INEXACT; |
437 | # endif |
438 | # ifdef FE_UNDERFLOW |
439 | if (fe_exc & FE_UNDERFLOW) |
440 | exception |= FE_INEXACT; |
441 | # endif |
442 | #endif |
443 | fedisableexcept (excepts: exception); |
444 | feraiseexcept (excepts: fe_exc); |
445 | exit (status: 2); |
446 | } |
447 | else if (pid < 0) |
448 | { |
449 | if (errno != ENOSYS) |
450 | { |
451 | printf (format: " Fail: Could not fork.\n" ); |
452 | ++count_errors; |
453 | } |
454 | else |
455 | printf (format: " `fork' not implemented, test ignored.\n" ); |
456 | } |
457 | else { |
458 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
459 | { |
460 | printf (format: " Fail: waitpid call failed.\n" ); |
461 | ++count_errors; |
462 | } |
463 | else if (WIFEXITED (status) && WEXITSTATUS (status) == 2) |
464 | printf (format: " Pass: Process exited normally.\n" ); |
465 | else |
466 | { |
467 | printf (format: " Fail: Process exited abnormally with status %d.\n" , |
468 | status); |
469 | ++count_errors; |
470 | } |
471 | } |
472 | } |
473 | |
474 | |
475 | /* Tests for feenableexcept/fedisableexcept/fegetexcept. */ |
476 | static void |
477 | feenable_test (const char *flag_name, int fe_exc) |
478 | { |
479 | int excepts; |
480 | |
481 | printf (format: "Tests for feenableexcepts etc. with flag %s\n" , flag_name); |
482 | |
483 | /* First disable all exceptions. */ |
484 | if (fedisableexcept (FE_ALL_EXCEPT) == -1) |
485 | { |
486 | printf (format: "Test: fedisableexcept (FE_ALL_EXCEPT) failed\n" ); |
487 | ++count_errors; |
488 | /* If this fails, the other tests don't make sense. */ |
489 | return; |
490 | } |
491 | excepts = fegetexcept (); |
492 | if (excepts != 0) |
493 | { |
494 | printf (format: "Test: fegetexcept (%s) failed, return should be 0, is %d\n" , |
495 | flag_name, excepts); |
496 | ++count_errors; |
497 | } |
498 | excepts = feenableexcept (excepts: fe_exc); |
499 | if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && excepts == -1) |
500 | { |
501 | printf (format: "Test: not testing feenableexcept, it isn't implemented.\n" ); |
502 | return; |
503 | } |
504 | if (excepts == -1) |
505 | { |
506 | printf (format: "Test: feenableexcept (%s) failed\n" , flag_name); |
507 | ++count_errors; |
508 | return; |
509 | } |
510 | if (excepts != 0) |
511 | { |
512 | printf (format: "Test: feenableexcept (%s) failed, return should be 0, is %x\n" , |
513 | flag_name, excepts); |
514 | ++count_errors; |
515 | } |
516 | |
517 | excepts = fegetexcept (); |
518 | if (excepts != fe_exc) |
519 | { |
520 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
521 | flag_name, fe_exc, excepts); |
522 | ++count_errors; |
523 | } |
524 | |
525 | /* And now disable the exception again. */ |
526 | excepts = fedisableexcept (excepts: fe_exc); |
527 | if (excepts == -1) |
528 | { |
529 | printf (format: "Test: fedisableexcept (%s) failed\n" , flag_name); |
530 | ++count_errors; |
531 | return; |
532 | } |
533 | if (excepts != fe_exc) |
534 | { |
535 | printf (format: "Test: fedisableexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
536 | flag_name, fe_exc, excepts); |
537 | ++count_errors; |
538 | } |
539 | |
540 | excepts = fegetexcept (); |
541 | if (excepts != 0) |
542 | { |
543 | printf (format: "Test: fegetexcept (%s) failed, return should be 0, is 0x%x\n" , |
544 | flag_name, excepts); |
545 | ++count_errors; |
546 | } |
547 | |
548 | /* Now the other way round: Enable all exceptions and disable just this one. */ |
549 | if (feenableexcept (FE_ALL_EXCEPT) == -1) |
550 | { |
551 | printf (format: "Test: feenableexcept (FE_ALL_EXCEPT) failed\n" ); |
552 | ++count_errors; |
553 | /* If this fails, the other tests don't make sense. */ |
554 | return; |
555 | } |
556 | |
557 | excepts = fegetexcept (); |
558 | if (excepts != FE_ALL_EXCEPT) |
559 | { |
560 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
561 | flag_name, FE_ALL_EXCEPT, excepts); |
562 | ++count_errors; |
563 | } |
564 | |
565 | excepts = fedisableexcept (excepts: fe_exc); |
566 | if (excepts == -1) |
567 | { |
568 | printf (format: "Test: fedisableexcept (%s) failed\n" , flag_name); |
569 | ++count_errors; |
570 | return; |
571 | } |
572 | if (excepts != FE_ALL_EXCEPT) |
573 | { |
574 | printf (format: "Test: fedisableexcept (%s) failed, return should be 0, is 0x%x\n" , |
575 | flag_name, excepts); |
576 | ++count_errors; |
577 | } |
578 | |
579 | excepts = fegetexcept (); |
580 | if (excepts != (FE_ALL_EXCEPT & ~fe_exc)) |
581 | { |
582 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
583 | flag_name, (FE_ALL_EXCEPT & ~fe_exc), excepts); |
584 | ++count_errors; |
585 | } |
586 | |
587 | /* And now enable the exception again. */ |
588 | excepts = feenableexcept (excepts: fe_exc); |
589 | if (excepts == -1) |
590 | { |
591 | printf (format: "Test: feenableexcept (%s) failed\n" , flag_name); |
592 | ++count_errors; |
593 | return; |
594 | } |
595 | if (excepts != (FE_ALL_EXCEPT & ~fe_exc)) |
596 | { |
597 | printf (format: "Test: feenableexcept (%s) failed, return should be 0, is 0x%x\n" , |
598 | flag_name, excepts); |
599 | ++count_errors; |
600 | } |
601 | |
602 | excepts = fegetexcept (); |
603 | if (excepts != FE_ALL_EXCEPT) |
604 | { |
605 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
606 | flag_name, FE_ALL_EXCEPT, excepts); |
607 | ++count_errors; |
608 | } |
609 | feexcp_nomask_test (flag_name, fe_exc); |
610 | feexcp_mask_test (flag_name, fe_exc); |
611 | |
612 | } |
613 | |
614 | |
615 | static void |
616 | fe_single_test (const char *flag_name, int fe_exc) |
617 | { |
618 | feenv_nomask_test (flag_name, fe_exc); |
619 | feenv_mask_test (flag_name, fe_exc); |
620 | feenable_test (flag_name, fe_exc); |
621 | } |
622 | #endif |
623 | |
624 | |
625 | static void |
626 | feenv_tests (void) |
627 | { |
628 | /* We might have some exceptions still set. */ |
629 | feclearexcept (FE_ALL_EXCEPT); |
630 | |
631 | #ifdef FE_DIVBYZERO |
632 | fe_single_test (flag_name: "FE_DIVBYZERO" , FE_DIVBYZERO); |
633 | #endif |
634 | #ifdef FE_INVALID |
635 | fe_single_test (flag_name: "FE_INVALID" , FE_INVALID); |
636 | #endif |
637 | #ifdef FE_INEXACT |
638 | fe_single_test (flag_name: "FE_INEXACT" , FE_INEXACT); |
639 | #endif |
640 | #ifdef FE_UNDERFLOW |
641 | fe_single_test (flag_name: "FE_UNDERFLOW" , FE_UNDERFLOW); |
642 | #endif |
643 | #ifdef FE_OVERFLOW |
644 | fe_single_test (flag_name: "FE_OVERFLOW" , FE_OVERFLOW); |
645 | #endif |
646 | fesetenv (FE_DFL_ENV); |
647 | } |
648 | |
649 | |
650 | static void |
651 | feholdexcept_tests (void) |
652 | { |
653 | fenv_t saved, saved2; |
654 | int res; |
655 | |
656 | feclearexcept (FE_ALL_EXCEPT); |
657 | fedisableexcept (FE_ALL_EXCEPT); |
658 | #ifdef FE_DIVBYZERO |
659 | feraiseexcept (FE_DIVBYZERO); |
660 | #endif |
661 | if (EXCEPTION_TESTS (float)) |
662 | test_exceptions (test_name: "feholdexcept_tests FE_DIVBYZERO test" , |
663 | DIVBYZERO_EXC, ignore_inexact: 0); |
664 | res = feholdexcept (envp: &saved); |
665 | if (res != 0) |
666 | { |
667 | printf (format: "feholdexcept failed: %d\n" , res); |
668 | ++count_errors; |
669 | } |
670 | #if defined FE_TONEAREST && defined FE_TOWARDZERO |
671 | res = fesetround (FE_TOWARDZERO); |
672 | if (res != 0 && ROUNDING_TESTS (float, FE_TOWARDZERO)) |
673 | { |
674 | printf (format: "fesetround failed: %d\n" , res); |
675 | ++count_errors; |
676 | } |
677 | #endif |
678 | test_exceptions (test_name: "feholdexcept_tests 0 test" , NO_EXC, ignore_inexact: 0); |
679 | #ifdef FE_INVALID |
680 | feraiseexcept (FE_INVALID); |
681 | if (EXCEPTION_TESTS (float)) |
682 | test_exceptions (test_name: "feholdexcept_tests FE_INVALID test" , |
683 | INVALID_EXC, ignore_inexact: 0); |
684 | #endif |
685 | res = feupdateenv (envp: &saved); |
686 | if (res != 0) |
687 | { |
688 | printf (format: "feupdateenv failed: %d\n" , res); |
689 | ++count_errors; |
690 | } |
691 | #if defined FE_TONEAREST && defined FE_TOWARDZERO |
692 | res = fegetround (); |
693 | if (res != FE_TONEAREST) |
694 | { |
695 | printf (format: "feupdateenv didn't restore rounding mode: %d\n" , res); |
696 | ++count_errors; |
697 | } |
698 | #endif |
699 | if (EXCEPTION_TESTS (float)) |
700 | test_exceptions (test_name: "feholdexcept_tests FE_DIVBYZERO|FE_INVALID test" , |
701 | DIVBYZERO_EXC | INVALID_EXC, ignore_inexact: 0); |
702 | feclearexcept (FE_ALL_EXCEPT); |
703 | #ifdef FE_INVALID |
704 | feraiseexcept (FE_INVALID); |
705 | #endif |
706 | #if defined FE_TONEAREST && defined FE_UPWARD |
707 | res = fesetround (FE_UPWARD); |
708 | if (res != 0 && ROUNDING_TESTS (float, FE_UPWARD)) |
709 | { |
710 | printf (format: "fesetround failed: %d\n" , res); |
711 | ++count_errors; |
712 | } |
713 | #endif |
714 | res = feholdexcept (envp: &saved2); |
715 | if (res != 0) |
716 | { |
717 | printf (format: "feholdexcept failed: %d\n" , res); |
718 | ++count_errors; |
719 | } |
720 | #if defined FE_TONEAREST && defined FE_UPWARD |
721 | res = fesetround (FE_TONEAREST); |
722 | if (res != 0) |
723 | { |
724 | printf (format: "fesetround failed: %d\n" , res); |
725 | ++count_errors; |
726 | } |
727 | #endif |
728 | test_exceptions (test_name: "feholdexcept_tests 0 2nd test" , NO_EXC, ignore_inexact: 0); |
729 | #ifdef FE_INEXACT |
730 | feraiseexcept (FE_INEXACT); |
731 | if (EXCEPTION_TESTS (float)) |
732 | test_exceptions (test_name: "feholdexcept_tests FE_INEXACT test" , |
733 | INEXACT_EXC, ignore_inexact: 0); |
734 | #endif |
735 | res = feupdateenv (envp: &saved2); |
736 | if (res != 0) |
737 | { |
738 | printf (format: "feupdateenv failed: %d\n" , res); |
739 | ++count_errors; |
740 | } |
741 | #if defined FE_TONEAREST && defined FE_UPWARD |
742 | res = fegetround (); |
743 | if (res != FE_UPWARD && ROUNDING_TESTS (float, FE_UPWARD)) |
744 | { |
745 | printf (format: "feupdateenv didn't restore rounding mode: %d\n" , res); |
746 | ++count_errors; |
747 | } |
748 | fesetround (FE_TONEAREST); |
749 | #endif |
750 | if (EXCEPTION_TESTS (float)) |
751 | test_exceptions (test_name: "feholdexcept_tests FE_INEXACT|FE_INVALID test" , |
752 | INVALID_EXC | INEXACT_EXC, ignore_inexact: 0); |
753 | feclearexcept (FE_ALL_EXCEPT); |
754 | } |
755 | |
756 | |
757 | /* IEC 559 and ISO C99 define a default startup environment */ |
758 | static void |
759 | initial_tests (void) |
760 | { |
761 | test_exceptions (test_name: "Initially all exceptions should be cleared" , |
762 | NO_EXC, ignore_inexact: 0); |
763 | #ifdef FE_TONEAREST |
764 | test_rounding (test_name: "Rounding direction should be initalized to nearest" , |
765 | FE_TONEAREST); |
766 | #endif |
767 | } |
768 | |
769 | int |
770 | main (void) |
771 | { |
772 | initial_tests (); |
773 | fe_tests (); |
774 | feenv_tests (); |
775 | feholdexcept_tests (); |
776 | |
777 | if (count_errors) |
778 | { |
779 | printf (format: "\n%d errors occurred.\n" , count_errors); |
780 | exit (status: 1); |
781 | } |
782 | printf (format: "\n All tests passed successfully.\n" ); |
783 | return 0; |
784 | } |
785 | |