2 * Copyright (c) 2004 David Schultz <das@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * Test the correctness and C99-compliance of various fenv.h features.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/types.h>
47 * Implementations are permitted to define additional exception flags
48 * not specified in the standard, so it is not necessarily true that
49 * FE_ALL_EXCEPT == ALL_STD_EXCEPT.
51 #define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
52 FE_OVERFLOW | FE_UNDERFLOW)
54 #define NEXCEPTS (sizeof(std_excepts) / sizeof(std_excepts[0]))
56 static const int std_excepts
[] = {
64 /* init_exceptsets() initializes this to the power set of std_excepts[] */
65 static int std_except_sets
[1 << NEXCEPTS
];
67 static void init_exceptsets(void);
69 static void test_dfl_env(void);
70 static void test_fegsetenv(void);
71 static void test_fegsetexceptflag(void);
72 static void test_masking(void);
73 static void test_fegsetround(void);
74 static void test_feholdupdate(void);
75 static void test_feraiseexcept(void);
76 static void test_fetestclearexcept(void);
78 static int getround(void);
79 static void raiseexcept(int excepts
);
80 static void trap_handler(int sig
);
82 #pragma STDC FENV_ACCESS ON
85 main(int argc
, char *argv
[])
91 printf("ok 1 - fenv\n");
92 test_fetestclearexcept();
93 printf("ok 2 - fenv\n");
94 test_fegsetexceptflag();
95 printf("ok 3 - fenv\n");
97 printf("ok 4 - fenv\n");
99 printf("ok 5 - fenv\n");
101 printf("ok 6 - fenv\n");
103 printf("ok 7 - fenv\n");
105 printf("ok 8 - fenv\n");
111 * Initialize std_except_sets[] to the power set of std_excepts[]
114 init_exceptsets(void)
118 for (i
= 0; i
< 1 << NEXCEPTS
; i
++) {
119 for (sr
= i
, j
= 0; sr
!= 0; sr
>>= 1, j
++)
120 std_except_sets
[i
] |= std_excepts
[j
] & ((~sr
& 1) - 1);
125 * This tests checks the default FP environment, so it must be first.
126 * The memcmp() test below may be too much to ask for, since there
127 * could be multiple machine-specific default environments.
132 #ifndef NO_STRICT_DFL_ENV
136 assert(memcmp(&env
, FE_DFL_ENV
, sizeof(env
)) == 0);
138 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
142 * Test fetestexcept() and feclearexcept().
145 test_fetestclearexcept(void)
149 for (i
= 0; i
< 1 << NEXCEPTS
; i
++)
150 assert(fetestexcept(std_except_sets
[i
]) == 0);
151 for (i
= 0; i
< 1 << NEXCEPTS
; i
++) {
152 excepts
= std_except_sets
[i
];
154 /* FE_ALL_EXCEPT might be special-cased, as on i386. */
155 raiseexcept(excepts
);
156 assert(fetestexcept(excepts
) == excepts
);
157 assert(feclearexcept(FE_ALL_EXCEPT
) == 0);
158 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
160 raiseexcept(excepts
);
161 assert(fetestexcept(excepts
) == excepts
);
162 if ((excepts
& (FE_UNDERFLOW
| FE_OVERFLOW
)) != 0) {
163 excepts
|= FE_INEXACT
;
164 assert((fetestexcept(ALL_STD_EXCEPT
) | FE_INEXACT
) ==
167 assert(fetestexcept(ALL_STD_EXCEPT
) == excepts
);
169 assert(feclearexcept(excepts
) == 0);
170 assert(fetestexcept(ALL_STD_EXCEPT
) == 0);
175 * Test fegetexceptflag() and fesetexceptflag().
177 * Prerequisites: fetestexcept(), feclearexcept()
180 test_fegsetexceptflag(void)
185 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
186 for (i
= 0; i
< 1 << NEXCEPTS
; i
++) {
187 excepts
= std_except_sets
[i
];
189 assert(fegetexceptflag(&flag
, excepts
) == 0);
190 raiseexcept(ALL_STD_EXCEPT
);
191 assert(fesetexceptflag(&flag
, excepts
) == 0);
192 assert(fetestexcept(ALL_STD_EXCEPT
) ==
193 (ALL_STD_EXCEPT
^ excepts
));
195 assert(fegetexceptflag(&flag
, FE_ALL_EXCEPT
) == 0);
196 assert(feclearexcept(FE_ALL_EXCEPT
) == 0);
197 assert(fesetexceptflag(&flag
, excepts
) == 0);
198 assert(fetestexcept(ALL_STD_EXCEPT
) == 0);
199 assert(fesetexceptflag(&flag
, ALL_STD_EXCEPT
^ excepts
) == 0);
200 assert(fetestexcept(ALL_STD_EXCEPT
) ==
201 (ALL_STD_EXCEPT
^ excepts
));
203 assert(feclearexcept(FE_ALL_EXCEPT
) == 0);
208 * Test feraiseexcept().
210 * Prerequisites: fetestexcept(), feclearexcept()
213 test_feraiseexcept(void)
217 for (i
= 0; i
< 1 << NEXCEPTS
; i
++) {
218 excepts
= std_except_sets
[i
];
220 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
221 assert(feraiseexcept(excepts
) == 0);
222 if ((excepts
& (FE_UNDERFLOW
| FE_OVERFLOW
)) != 0) {
223 excepts
|= FE_INEXACT
;
224 assert((fetestexcept(ALL_STD_EXCEPT
) | FE_INEXACT
) ==
227 assert(fetestexcept(ALL_STD_EXCEPT
) == excepts
);
229 assert(feclearexcept(FE_ALL_EXCEPT
) == 0);
231 assert(feraiseexcept(FE_INVALID
| FE_DIVBYZERO
) == 0);
232 assert(fetestexcept(ALL_STD_EXCEPT
) == (FE_INVALID
| FE_DIVBYZERO
));
233 assert(feraiseexcept(FE_OVERFLOW
| FE_UNDERFLOW
| FE_INEXACT
) == 0);
234 assert(fetestexcept(ALL_STD_EXCEPT
) == ALL_STD_EXCEPT
);
235 assert(feclearexcept(FE_ALL_EXCEPT
) == 0);
239 * Test fegetround() and fesetround().
242 test_fegsetround(void)
245 assert(fegetround() == FE_TONEAREST
);
246 assert(getround() == FE_TONEAREST
);
247 assert(FLT_ROUNDS
== 1);
249 assert(fesetround(FE_DOWNWARD
) == 0);
250 assert(fegetround() == FE_DOWNWARD
);
251 assert(getround() == FE_DOWNWARD
);
252 assert(FLT_ROUNDS
== 3);
254 assert(fesetround(FE_UPWARD
) == 0);
255 assert(getround() == FE_UPWARD
);
256 assert(fegetround() == FE_UPWARD
);
257 assert(FLT_ROUNDS
== 2);
259 assert(fesetround(FE_TOWARDZERO
) == 0);
260 assert(getround() == FE_TOWARDZERO
);
261 assert(fegetround() == FE_TOWARDZERO
);
262 assert(FLT_ROUNDS
== 0);
264 assert(fesetround(FE_TONEAREST
) == 0);
265 assert(getround() == FE_TONEAREST
);
266 assert(FLT_ROUNDS
== 1);
268 assert(feclearexcept(FE_ALL_EXCEPT
) == 0);
272 * Test fegetenv() and fesetenv().
274 * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround()
282 for (i
= 0; i
< 1 << NEXCEPTS
; i
++) {
283 excepts
= std_except_sets
[i
];
285 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
286 assert(fegetround() == FE_TONEAREST
);
287 assert(fegetenv(&env1
) == 0);
290 * fe[gs]etenv() should be able to save and restore
291 * exception flags without the spurious inexact
292 * exceptions that afflict raiseexcept().
294 raiseexcept(excepts
);
295 if ((excepts
& (FE_UNDERFLOW
| FE_OVERFLOW
)) != 0 &&
296 (excepts
& FE_INEXACT
) == 0)
297 assert(feclearexcept(FE_INEXACT
) == 0);
299 fesetround(FE_DOWNWARD
);
300 assert(fegetenv(&env2
) == 0);
301 assert(fesetenv(&env1
) == 0);
302 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
303 assert(fegetround() == FE_TONEAREST
);
305 assert(fesetenv(&env2
) == 0);
306 assert(fetestexcept(FE_ALL_EXCEPT
) == excepts
);
307 assert(fegetround() == FE_DOWNWARD
);
308 assert(fesetenv(&env1
) == 0);
309 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
310 assert(fegetround() == FE_TONEAREST
);
315 * Test fegetexcept(), fedisableexcept(), and feenableexcept().
317 * Prerequisites: fetestexcept(), feraiseexcept()
322 struct sigaction act
;
323 int except
, i
, pass
, raise
, status
;
325 assert((fegetexcept() & ALL_STD_EXCEPT
) == 0);
326 assert((feenableexcept(FE_INVALID
|FE_OVERFLOW
) & ALL_STD_EXCEPT
) == 0);
327 assert((feenableexcept(FE_UNDERFLOW
) & ALL_STD_EXCEPT
) ==
328 (FE_INVALID
| FE_OVERFLOW
));
329 assert((fedisableexcept(FE_OVERFLOW
) & ALL_STD_EXCEPT
) ==
330 (FE_INVALID
| FE_OVERFLOW
| FE_UNDERFLOW
));
331 assert((fegetexcept() & ALL_STD_EXCEPT
) == (FE_INVALID
| FE_UNDERFLOW
));
332 assert((fedisableexcept(FE_ALL_EXCEPT
) & ALL_STD_EXCEPT
) ==
333 (FE_INVALID
| FE_UNDERFLOW
));
334 assert((fegetexcept() & ALL_STD_EXCEPT
) == 0);
336 sigemptyset(&act
.sa_mask
);
338 act
.sa_handler
= trap_handler
;
339 for (pass
= 0; pass
< 2; pass
++) {
340 for (i
= 0; i
< NEXCEPTS
; i
++) {
341 except
= std_excepts
[i
];
342 /* over/underflow may also raise inexact */
343 if (except
== FE_INEXACT
)
344 raise
= FE_DIVBYZERO
| FE_INVALID
;
346 raise
= ALL_STD_EXCEPT
^ except
;
349 * We need to fork a child process because
350 * there isn't a portable way to recover from
351 * a floating-point exception.
355 assert((fegetexcept() & ALL_STD_EXCEPT
) == 0);
356 assert((feenableexcept(except
)
357 & ALL_STD_EXCEPT
) == 0);
358 assert(fegetexcept() == except
);
360 assert(feraiseexcept(raise
) == 0);
361 assert(fetestexcept(ALL_STD_EXCEPT
) == raise
);
363 assert(sigaction(SIGFPE
, &act
, NULL
) == 0);
368 feraiseexcept(except
);
373 default: /* parent */
374 assert(wait(&status
) > 0);
376 * Avoid assert() here so that it's possible
377 * to examine a failed child's core dump.
379 if (!WIFEXITED(status
))
380 errx(1, "child aborted\n");
381 assert(WEXITSTATUS(status
) == 0);
388 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
392 * Test feholdexcept() and feupdateenv().
394 * Prerequisites: fetestexcept(), fegetround(), fesetround(),
395 * fedisableexcept(), feenableexcept()
398 test_feholdupdate(void)
402 struct sigaction act
;
403 int except
, i
, pass
, status
, raise
;
405 sigemptyset(&act
.sa_mask
);
407 act
.sa_handler
= trap_handler
;
408 for (pass
= 0; pass
< 2; pass
++) {
409 for (i
= 0; i
< NEXCEPTS
; i
++) {
410 except
= std_excepts
[i
];
411 /* over/underflow may also raise inexact */
412 if (except
== FE_INEXACT
)
413 raise
= FE_DIVBYZERO
| FE_INVALID
;
415 raise
= ALL_STD_EXCEPT
^ except
;
418 * We need to fork a child process because
419 * there isn't a portable way to recover from
420 * a floating-point exception.
425 * We don't want to cause a fatal exception in
426 * the child until the second pass, so we can
427 * check other properties of feupdateenv().
430 assert((feenableexcept(except
) &
431 ALL_STD_EXCEPT
) == 0);
433 assert(fesetround(FE_DOWNWARD
) == 0);
434 assert(feholdexcept(&env
) == 0);
435 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
437 assert(fesetround(FE_UPWARD
) == 0);
440 assert(sigaction(SIGFPE
, &act
, NULL
) ==
442 assert(feupdateenv(&env
) == 0);
443 assert(fegetround() == FE_DOWNWARD
);
444 assert(fetestexcept(ALL_STD_EXCEPT
) ==
449 default: /* parent */
450 assert(wait(&status
) > 0);
452 * Avoid assert() here so that it's possible
453 * to examine a failed child's core dump.
455 if (!WIFEXITED(status
))
456 errx(1, "child aborted\n");
457 assert(WEXITSTATUS(status
) == 0);
464 assert(fetestexcept(FE_ALL_EXCEPT
) == 0);
468 * Raise a floating-point exception without relying on the standard
469 * library routines, which we are trying to test.
471 * XXX We can't raise an {over,under}flow without also raising an
475 raiseexcept(int excepts
)
480 * With a compiler that supports the FENV_ACCESS pragma
481 * properly, simple expressions like '0.0 / 0.0' should
482 * be sufficient to generate traps. Unfortunately, we
483 * need to bring a volatile variable into the equation
484 * to prevent incorrect optimizations.
486 if (excepts
& FE_INVALID
) {
490 if (excepts
& FE_DIVBYZERO
) {
494 if (excepts
& FE_OVERFLOW
) {
498 if (excepts
& FE_UNDERFLOW
) {
502 if (excepts
& FE_INEXACT
) {
508 * On the x86 (and some other architectures?) the FPU and
509 * integer units are decoupled. We need to execute an FWAIT
510 * or a floating-point instruction to get synchronous exceptions.
517 * Determine the current rounding mode without relying on the fenv
518 * routines. This function may raise an inexact exception.
526 * This test works just as well with 0.0 - 0.0, except on ia64
527 * where 0.0 - 0.0 gives the wrong sign when rounding downwards.
531 if (copysign(1.0, d
) < 0.0)
532 return (FE_DOWNWARD
);
535 if (d
+ (DBL_EPSILON
* 3.0 / 4.0) == 1.0)
536 return (FE_TOWARDZERO
);
537 if (d
+ (DBL_EPSILON
* 1.0 / 4.0) > 1.0)
540 return (FE_TONEAREST
);
544 trap_handler(int sig
)
547 assert(sig
== SIGFPE
);