fenv_test.c revision 143710
1105464Sphk/*-
2105464Sphk * Copyright (c) 2004 David Schultz <das@FreeBSD.org>
3105464Sphk * All rights reserved.
4105464Sphk *
5105464Sphk * Redistribution and use in source and binary forms, with or without
6105464Sphk * modification, are permitted provided that the following conditions
7105464Sphk * are met:
8105464Sphk * 1. Redistributions of source code must retain the above copyright
9105464Sphk *    notice, this list of conditions and the following disclaimer.
10105464Sphk * 2. Redistributions in binary form must reproduce the above copyright
11105464Sphk *    notice, this list of conditions and the following disclaimer in the
12105464Sphk *    documentation and/or other materials provided with the distribution.
13105464Sphk *
14105464Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15105464Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16105464Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17105464Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18105464Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19105464Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20105464Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21105464Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22105464Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23105464Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24105464Sphk * SUCH DAMAGE.
25105464Sphk */
26105464Sphk
27105464Sphk/*
28105464Sphk * Test the correctness and C99-compliance of various fenv.h features.
29105464Sphk */
30105464Sphk
31105464Sphk#include <sys/cdefs.h>
32105464Sphk__FBSDID("$FreeBSD: head/tools/regression/lib/msun/test-fenv.c 143710 2005-03-16 19:04:45Z das $");
33139778Simp
34139778Simp#include <sys/types.h>
35105464Sphk#include <sys/wait.h>
36105464Sphk#include <assert.h>
37105464Sphk#include <err.h>
38105464Sphk#include <fenv.h>
39105464Sphk#include <float.h>
40105464Sphk#include <math.h>
41105464Sphk#include <signal.h>
42105464Sphk#include <stdio.h>
43105464Sphk#include <string.h>
44105464Sphk#include <unistd.h>
45105464Sphk
46113010Sphk/*
47105464Sphk * Implementations are permitted to define additional exception flags
48105464Sphk * not specified in the standard, so it is not necessarily true that
49143418Sume * FE_ALL_EXCEPT == ALL_STD_EXCEPT.
50106407Sphk */
51106407Sphk#define	ALL_STD_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
52105464Sphk			 FE_OVERFLOW | FE_UNDERFLOW)
53105464Sphk
54105464Sphk#define	NEXCEPTS	(sizeof(std_excepts) / sizeof(std_excepts[0]))
55114167Sphk
56114167Sphkstatic const int std_excepts[] = {
57114167Sphk	FE_INVALID,
58114167Sphk	FE_DIVBYZERO,
59105464Sphk	FE_OVERFLOW,
60105464Sphk	FE_UNDERFLOW,
61105464Sphk	FE_INEXACT,
62105464Sphk};
63105464Sphk
64105464Sphk/* init_exceptsets() initializes this to the power set of std_excepts[] */
65105464Sphkstatic int std_except_sets[1 << NEXCEPTS];
66105464Sphk
67148192Sphkstatic void init_exceptsets(void);
68105464Sphk
69106226Sphkstatic void test_dfl_env(void);
70106226Sphkstatic void test_fegsetenv(void);
71106226Sphkstatic void test_fegsetexceptflag(void);
72105464Sphkstatic void test_masking(void);
73106226Sphkstatic void test_fegsetround(void);
74106226Sphkstatic void test_feholdupdate(void);
75105464Sphkstatic void test_feraiseexcept(void);
76106226Sphkstatic void test_fetestclearexcept(void);
77105464Sphk
78105464Sphkstatic int getround(void);
79105464Sphkstatic void raiseexcept(int excepts);
80105464Sphkstatic void trap_handler(int sig);
81105464Sphk
82106226Sphk#pragma STDC FENV_ACCESS ON
83105464Sphk
84106226Sphkint
85106407Sphkmain(int argc, char *argv[])
86105464Sphk{
87106407Sphk
88113010Sphk	printf("1..8\n");
89106407Sphk	init_exceptsets();
90105464Sphk	test_dfl_env();
91106226Sphk	printf("ok 1 - fenv\n");
92106407Sphk	test_fetestclearexcept();
93106226Sphk	printf("ok 2 - fenv\n");
94106226Sphk	test_fegsetexceptflag();
95106226Sphk	printf("ok 3 - fenv\n");
96106226Sphk	test_feraiseexcept();
97106226Sphk	printf("ok 4 - fenv\n");
98106226Sphk	test_fegsetround();
99106226Sphk	printf("ok 5 - fenv\n");
100106407Sphk	test_fegsetenv();
101105464Sphk	printf("ok 6 - fenv\n");
102106407Sphk	test_masking();
103105464Sphk	printf("ok 7 - fenv\n");
104105464Sphk	test_feholdupdate();
105105464Sphk	printf("ok 8 - fenv\n");
106105464Sphk
107105464Sphk	return (0);
108105464Sphk}
109105464Sphk
110105464Sphk/*
111105464Sphk * Initialize std_except_sets[] to the power set of std_excepts[]
112105464Sphk */
113105464Sphkvoid
114105464Sphkinit_exceptsets(void)
115105464Sphk{
116105464Sphk	int i, j, sr;
117105464Sphk
118105464Sphk	for (i = 0; i < 1 << NEXCEPTS; i++) {
119105464Sphk		for (sr = i, j = 0; sr != 0; sr >>= 1, j++)
120105464Sphk			std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1);
121105464Sphk	}
122105464Sphk}
123105464Sphk
124105464Sphk/*
125105464Sphk * This tests checks the default FP environment, so it must be first.
126105464Sphk * The memcmp() test below may be too much to ask for, since there
127105464Sphk * could be multiple machine-specific default environments.
128105464Sphk */
129105464Sphkstatic void
130105464Sphktest_dfl_env(void)
131105464Sphk{
132105464Sphk#ifndef NO_STRICT_DFL_ENV
133105464Sphk	fenv_t env;
134105464Sphk
135105464Sphk	fegetenv(&env);
136105464Sphk	assert(memcmp(&env, FE_DFL_ENV, sizeof(env)) == 0);
137105464Sphk#endif
138105464Sphk	assert(fetestexcept(FE_ALL_EXCEPT) == 0);
139105464Sphk}
140119809Sphk
141105464Sphk/*
142105464Sphk * Test fetestexcept() and feclearexcept().
143105464Sphk */
144105464Sphkstatic void
145105464Sphktest_fetestclearexcept(void)
146105464Sphk{
147105464Sphk	int excepts, i;
148105464Sphk
149105464Sphk	for (i = 0; i < 1 << NEXCEPTS; i++)
150105464Sphk		assert(fetestexcept(std_except_sets[i]) == 0);
151105464Sphk	for (i = 0; i < 1 << NEXCEPTS; i++) {
152105464Sphk		excepts = std_except_sets[i];
153105464Sphk
154105464Sphk		/* FE_ALL_EXCEPT might be special-cased, as on i386. */
155105464Sphk		raiseexcept(excepts);
156105464Sphk		assert(fetestexcept(excepts) == excepts);
157105464Sphk		assert(feclearexcept(FE_ALL_EXCEPT) == 0);
158105464Sphk		assert(fetestexcept(FE_ALL_EXCEPT) == 0);
159105464Sphk
160105464Sphk		raiseexcept(excepts);
161105464Sphk		assert(fetestexcept(excepts) == excepts);
162105464Sphk		if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) {
163105464Sphk			excepts |= FE_INEXACT;
164105464Sphk			assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) ==
165105464Sphk			    excepts);
166105464Sphk		} else {
167105464Sphk			assert(fetestexcept(ALL_STD_EXCEPT) == excepts);
168115505Sphk		}
169105464Sphk		assert(feclearexcept(excepts) == 0);
170105464Sphk		assert(fetestexcept(ALL_STD_EXCEPT) == 0);
171105464Sphk	}
172105464Sphk}
173105464Sphk
174105464Sphk/*
175105464Sphk * Test fegetexceptflag() and fesetexceptflag().
176105464Sphk *
177105464Sphk * Prerequisites: fetestexcept(), feclearexcept()
178105464Sphk */
179119891Sphkstatic void
180105464Sphktest_fegsetexceptflag(void)
181105464Sphk{
182105464Sphk	fexcept_t flag;
183105464Sphk	int excepts, i;
184105464Sphk
185105464Sphk	assert(fetestexcept(FE_ALL_EXCEPT) == 0);
186105464Sphk	for (i = 0; i < 1 << NEXCEPTS; i++) {
187105464Sphk		excepts = std_except_sets[i];
188105464Sphk
189105464Sphk		assert(fegetexceptflag(&flag, excepts) == 0);
190105464Sphk		raiseexcept(ALL_STD_EXCEPT);
191105464Sphk		assert(fesetexceptflag(&flag, excepts) == 0);
192105464Sphk		assert(fetestexcept(ALL_STD_EXCEPT) ==
193105464Sphk		    (ALL_STD_EXCEPT ^ excepts));
194105464Sphk
195105464Sphk		assert(fegetexceptflag(&flag, FE_ALL_EXCEPT) == 0);
196105464Sphk		assert(feclearexcept(FE_ALL_EXCEPT) == 0);
197105464Sphk		assert(fesetexceptflag(&flag, excepts) == 0);
198107451Sphk		assert(fetestexcept(ALL_STD_EXCEPT) == 0);
199107451Sphk		assert(fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts) == 0);
200107451Sphk		assert(fetestexcept(ALL_STD_EXCEPT) ==
201105464Sphk		    (ALL_STD_EXCEPT ^ excepts));
202105464Sphk
203105464Sphk		assert(feclearexcept(FE_ALL_EXCEPT) == 0);
204107451Sphk	}
205105464Sphk}
206105464Sphk
207105464Sphk/*
208105464Sphk * Test feraiseexcept().
209105464Sphk *
210105464Sphk * Prerequisites: fetestexcept(), feclearexcept()
211105464Sphk */
212105464Sphkstatic void
213115505Sphktest_feraiseexcept(void)
214107451Sphk{
215107451Sphk	int excepts, i;
216105464Sphk
217105464Sphk	for (i = 0; i < 1 << NEXCEPTS; i++) {
218105464Sphk		excepts = std_except_sets[i];
219105464Sphk
220105464Sphk		assert(fetestexcept(FE_ALL_EXCEPT) == 0);
221105464Sphk		assert(feraiseexcept(excepts) == 0);
222105464Sphk		if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) {
223105464Sphk			excepts |= FE_INEXACT;
224105464Sphk			assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) ==
225105464Sphk			    excepts);
226105464Sphk		} else {
227105464Sphk			assert(fetestexcept(ALL_STD_EXCEPT) == excepts);
228105464Sphk		}
229105464Sphk		assert(feclearexcept(FE_ALL_EXCEPT) == 0);
230105464Sphk	}
231105464Sphk	assert(feraiseexcept(FE_INVALID | FE_DIVBYZERO) == 0);
232105464Sphk	assert(fetestexcept(ALL_STD_EXCEPT) == (FE_INVALID | FE_DIVBYZERO));
233105464Sphk	assert(feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) == 0);
234105464Sphk	assert(fetestexcept(ALL_STD_EXCEPT) == ALL_STD_EXCEPT);
235105464Sphk	assert(feclearexcept(FE_ALL_EXCEPT) == 0);
236105464Sphk}
237105464Sphk
238105464Sphk/*
239105464Sphk * Test fegetround() and fesetround().
240105464Sphk */
241105464Sphkstatic void
242105464Sphktest_fegsetround(void)
243105464Sphk{
244105464Sphk
245105464Sphk	assert(fegetround() == FE_TONEAREST);
246105464Sphk	assert(getround() == FE_TONEAREST);
247105464Sphk	assert(FLT_ROUNDS == 1);
248105464Sphk
249105464Sphk	assert(fesetround(FE_DOWNWARD) == 0);
250105464Sphk	assert(fegetround() == FE_DOWNWARD);
251105464Sphk	assert(getround() == FE_DOWNWARD);
252108558Sphk	assert(FLT_ROUNDS == 3);
253108558Sphk
254105464Sphk	assert(fesetround(FE_UPWARD) == 0);
255108558Sphk	assert(getround() == FE_UPWARD);
256108558Sphk	assert(fegetround() == FE_UPWARD);
257108558Sphk	assert(FLT_ROUNDS == 2);
258108558Sphk
259108558Sphk	assert(fesetround(FE_TOWARDZERO) == 0);
260105464Sphk	assert(getround() == FE_TOWARDZERO);
261105464Sphk	assert(fegetround() == FE_TOWARDZERO);
262105464Sphk	assert(FLT_ROUNDS == 0);
263105464Sphk
264105464Sphk	assert(fesetround(FE_TONEAREST) == 0);
265105464Sphk	assert(getround() == FE_TONEAREST);
266105464Sphk	assert(FLT_ROUNDS == 1);
267105464Sphk
268105464Sphk	assert(feclearexcept(FE_ALL_EXCEPT) == 0);
269108558Sphk}
270105464Sphk
271105464Sphk/*
272108558Sphk * Test fegetenv() and fesetenv().
273108558Sphk *
274108558Sphk * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround()
275108558Sphk */
276105464Sphkstatic void
277108558Sphktest_fegsetenv(void)
278108558Sphk{
279105464Sphk	fenv_t env1, env2;
280108558Sphk	int excepts, i;
281108558Sphk
282108558Sphk	for (i = 0; i < 1 << NEXCEPTS; i++) {
283105464Sphk		excepts = std_except_sets[i];
284108558Sphk
285108558Sphk		assert(fetestexcept(FE_ALL_EXCEPT) == 0);
286105464Sphk		assert(fegetround() == FE_TONEAREST);
287108558Sphk		assert(fegetenv(&env1) == 0);
288108558Sphk
289111964Sphk		/*
290111964Sphk		 * fe[gs]etenv() should be able to save and restore
291111964Sphk		 * exception flags without the spurious inexact
292111964Sphk		 * exceptions that afflict raiseexcept().
293111964Sphk		 */
294108558Sphk		raiseexcept(excepts);
295108558Sphk		if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 &&
296105464Sphk		    (excepts & FE_INEXACT) == 0)
297108558Sphk			assert(feclearexcept(FE_INEXACT) == 0);
298108558Sphk
299108558Sphk		fesetround(FE_DOWNWARD);
300108558Sphk		assert(fegetenv(&env2) == 0);
301114251Sphk		assert(fesetenv(&env1) == 0);
302114251Sphk		assert(fetestexcept(FE_ALL_EXCEPT) == 0);
303108558Sphk		assert(fegetround() == FE_TONEAREST);
304108558Sphk
305105464Sphk		assert(fesetenv(&env2) == 0);
306108558Sphk		assert(fetestexcept(FE_ALL_EXCEPT) == excepts);
307108558Sphk		assert(fegetround() == FE_DOWNWARD);
308108558Sphk		assert(fesetenv(&env1) == 0);
309108558Sphk		assert(fetestexcept(FE_ALL_EXCEPT) == 0);
310105464Sphk		assert(fegetround() == FE_TONEAREST);
311108558Sphk	}
312108558Sphk}
313108558Sphk
314135085Sphk/*
315105464Sphk * Test fegetexcept(), fedisableexcept(), and feenableexcept().
316108558Sphk *
317108558Sphk * Prerequisites: fetestexcept(), feraiseexcept()
318105464Sphk */
319108558Sphkstatic void
320108558Sphktest_masking(void)
321108558Sphk{
322108558Sphk	struct sigaction act;
323108558Sphk	int except, i, pass, raise, status;
324108558Sphk
325108558Sphk	assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
326108558Sphk	assert((feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT) == 0);
327108558Sphk	assert((feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT) ==
328105464Sphk	    (FE_INVALID | FE_OVERFLOW));
329108558Sphk	assert((fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT) ==
330108558Sphk	    (FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW));
331108558Sphk	assert((fegetexcept() & ALL_STD_EXCEPT) == (FE_INVALID | FE_UNDERFLOW));
332108558Sphk	assert((fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT) ==
333108558Sphk	    (FE_INVALID | FE_UNDERFLOW));
334108558Sphk	assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
335105464Sphk
336114251Sphk	sigemptyset(&act.sa_mask);
337114543Sphk	act.sa_flags = 0;
338114251Sphk	act.sa_handler = trap_handler;
339114251Sphk	for (pass = 0; pass < 2; pass++) {
340114251Sphk		for (i = 0; i < NEXCEPTS; i++) {
341114251Sphk			except = std_excepts[i];
342114251Sphk			/* over/underflow may also raise inexact */
343114251Sphk			if (except == FE_INEXACT)
344114543Sphk				raise = FE_DIVBYZERO | FE_INVALID;
345114251Sphk			else
346114251Sphk				raise = ALL_STD_EXCEPT ^ except;
347114251Sphk
348114251Sphk			/*
349114251Sphk			 * We need to fork a child process because
350114543Sphk			 * there isn't a portable way to recover from
351114251Sphk			 * a floating-point exception.
352114251Sphk			 */
353114251Sphk			switch(fork()) {
354114251Sphk			case 0:		/* child */
355114251Sphk				assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
356114543Sphk				assert((feenableexcept(except)
357114251Sphk					   & ALL_STD_EXCEPT) == 0);
358114251Sphk				assert(fegetexcept() == except);
359114251Sphk				raiseexcept(raise);
360105464Sphk				assert(feraiseexcept(raise) == 0);
361				assert(fetestexcept(ALL_STD_EXCEPT) == raise);
362
363				assert(sigaction(SIGFPE, &act, NULL) == 0);
364				switch (pass) {
365				case 0:
366					raiseexcept(except);
367				case 1:
368					feraiseexcept(except);
369				default:
370					assert(0);
371				}
372				assert(0);
373			default:	/* parent */
374				assert(wait(&status) > 0);
375				/*
376				 * Avoid assert() here so that it's possible
377				 * to examine a failed child's core dump.
378				 */
379				if (!WIFEXITED(status))
380					errx(1, "child aborted\n");
381				assert(WEXITSTATUS(status) == 0);
382				break;
383			case -1:	/* error */
384				assert(0);
385			}
386		}
387	}
388	assert(fetestexcept(FE_ALL_EXCEPT) == 0);
389}
390
391/*
392 * Test feholdexcept() and feupdateenv().
393 *
394 * Prerequisites: fetestexcept(), fegetround(), fesetround(),
395 *	fedisableexcept(), feenableexcept()
396 */
397static void
398test_feholdupdate(void)
399{
400	fenv_t env;
401
402	struct sigaction act;
403	int except, i, pass, status, raise;
404
405	sigemptyset(&act.sa_mask);
406	act.sa_flags = 0;
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;
414			else
415				raise = ALL_STD_EXCEPT ^ except;
416
417			/*
418			 * We need to fork a child process because
419			 * there isn't a portable way to recover from
420			 * a floating-point exception.
421			 */
422			switch(fork()) {
423			case 0:		/* child */
424				/*
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().
428				 */
429				if (pass == 1)
430					assert((feenableexcept(except) &
431						   ALL_STD_EXCEPT) == 0);
432				raiseexcept(raise);
433				assert(fesetround(FE_DOWNWARD) == 0);
434				assert(feholdexcept(&env) == 0);
435				assert(fetestexcept(FE_ALL_EXCEPT) == 0);
436				raiseexcept(except);
437				assert(fesetround(FE_UPWARD) == 0);
438
439				if (pass == 1)
440					assert(sigaction(SIGFPE, &act, NULL) ==
441					    0);
442				assert(feupdateenv(&env) == 0);
443				assert(fegetround() == FE_DOWNWARD);
444				assert(fetestexcept(ALL_STD_EXCEPT) ==
445				    (except | raise));
446
447				assert(pass == 0);
448				_exit(0);
449			default:	/* parent */
450				assert(wait(&status) > 0);
451				/*
452				 * Avoid assert() here so that it's possible
453				 * to examine a failed child's core dump.
454				 */
455				if (!WIFEXITED(status))
456					errx(1, "child aborted\n");
457				assert(WEXITSTATUS(status) == 0);
458				break;
459			case -1:	/* error */
460				assert(0);
461			}
462		}
463	}
464	assert(fetestexcept(FE_ALL_EXCEPT) == 0);
465}
466
467/*
468 * Raise a floating-point exception without relying on the standard
469 * library routines, which we are trying to test.
470 *
471 * XXX We can't raise an {over,under}flow without also raising an
472 * inexact exception.
473 */
474static void
475raiseexcept(int excepts)
476{
477	volatile double d;
478
479	/*
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.
485	 */
486	if (excepts & FE_INVALID) {
487		d = 0.0;
488		d = 0.0 / d;
489	}
490	if (excepts & FE_DIVBYZERO) {
491		d = 0.0;
492		d = 1.0 / d;
493	}
494	if (excepts & FE_OVERFLOW) {
495		d = DBL_MAX;
496		d *= 2.0;
497	}
498	if (excepts & FE_UNDERFLOW) {
499		d = DBL_MIN;
500		d /= DBL_MAX;
501	}
502	if (excepts & FE_INEXACT) {
503		d = DBL_MIN;
504		d += 1.0;
505	}
506
507	/*
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.
511	 */
512	d = 1.0;
513	d += 1.0;
514}
515
516/*
517 * Determine the current rounding mode without relying on the fenv
518 * routines.  This function may raise an inexact exception.
519 */
520static int
521getround(void)
522{
523	volatile double d;
524
525	/*
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.
528	 */
529	d = 1.0;
530	d -= 1.0;
531	if (copysign(1.0, d) < 0.0)
532		return (FE_DOWNWARD);
533
534	d = 1.0;
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)
538		return (FE_UPWARD);
539
540	return (FE_TONEAREST);
541}
542
543static void
544trap_handler(int sig)
545{
546
547	assert(sig == SIGFPE);
548	_exit(0);
549}
550