1130330Sdas/*- 2130330Sdas * Copyright (c) 2004 David Schultz <das@FreeBSD.org> 3130330Sdas * All rights reserved. 4130330Sdas * 5130330Sdas * Redistribution and use in source and binary forms, with or without 6130330Sdas * modification, are permitted provided that the following conditions 7130330Sdas * are met: 8130330Sdas * 1. Redistributions of source code must retain the above copyright 9130330Sdas * notice, this list of conditions and the following disclaimer. 10130330Sdas * 2. Redistributions in binary form must reproduce the above copyright 11130330Sdas * notice, this list of conditions and the following disclaimer in the 12130330Sdas * documentation and/or other materials provided with the distribution. 13130330Sdas * 14130330Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15130330Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16130330Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17130330Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18130330Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19130330Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20130330Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21130330Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22130330Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23130330Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24130330Sdas * SUCH DAMAGE. 25130330Sdas */ 26130330Sdas 27130330Sdas/* 28130330Sdas * Test the correctness and C99-compliance of various fenv.h features. 29130330Sdas */ 30130330Sdas 31130330Sdas#include <sys/cdefs.h> 32130330Sdas__FBSDID("$FreeBSD$"); 33130330Sdas 34130330Sdas#include <sys/types.h> 35130330Sdas#include <sys/wait.h> 36130330Sdas#include <assert.h> 37130330Sdas#include <err.h> 38130330Sdas#include <fenv.h> 39130330Sdas#include <float.h> 40130330Sdas#include <math.h> 41130330Sdas#include <signal.h> 42130330Sdas#include <stdio.h> 43130330Sdas#include <string.h> 44130330Sdas#include <unistd.h> 45130330Sdas 46130330Sdas/* 47130330Sdas * Implementations are permitted to define additional exception flags 48130330Sdas * not specified in the standard, so it is not necessarily true that 49130330Sdas * FE_ALL_EXCEPT == ALL_STD_EXCEPT. 50130330Sdas */ 51130330Sdas#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ 52130330Sdas FE_OVERFLOW | FE_UNDERFLOW) 53130330Sdas 54130330Sdas#define NEXCEPTS (sizeof(std_excepts) / sizeof(std_excepts[0])) 55130330Sdas 56130330Sdasstatic const int std_excepts[] = { 57130330Sdas FE_INVALID, 58130330Sdas FE_DIVBYZERO, 59130330Sdas FE_OVERFLOW, 60130330Sdas FE_UNDERFLOW, 61130330Sdas FE_INEXACT, 62130330Sdas}; 63130330Sdas 64130330Sdas/* init_exceptsets() initializes this to the power set of std_excepts[] */ 65130330Sdasstatic int std_except_sets[1 << NEXCEPTS]; 66130330Sdas 67130330Sdasstatic void init_exceptsets(void); 68130330Sdas 69130330Sdasstatic void test_dfl_env(void); 70130330Sdasstatic void test_fegsetenv(void); 71130330Sdasstatic void test_fegsetexceptflag(void); 72143710Sdasstatic void test_masking(void); 73130330Sdasstatic void test_fegsetround(void); 74130330Sdasstatic void test_feholdupdate(void); 75130330Sdasstatic void test_feraiseexcept(void); 76130330Sdasstatic void test_fetestclearexcept(void); 77130330Sdas 78130330Sdasstatic int getround(void); 79130330Sdasstatic void raiseexcept(int excepts); 80130330Sdasstatic void trap_handler(int sig); 81130330Sdas 82130330Sdas#pragma STDC FENV_ACCESS ON 83130330Sdas 84130330Sdasint 85130330Sdasmain(int argc, char *argv[]) 86130330Sdas{ 87130330Sdas 88143710Sdas printf("1..8\n"); 89130330Sdas init_exceptsets(); 90130330Sdas test_dfl_env(); 91143710Sdas printf("ok 1 - fenv\n"); 92130330Sdas test_fetestclearexcept(); 93143710Sdas printf("ok 2 - fenv\n"); 94130330Sdas test_fegsetexceptflag(); 95143710Sdas printf("ok 3 - fenv\n"); 96130330Sdas test_feraiseexcept(); 97143710Sdas printf("ok 4 - fenv\n"); 98130330Sdas test_fegsetround(); 99143710Sdas printf("ok 5 - fenv\n"); 100130330Sdas test_fegsetenv(); 101143710Sdas printf("ok 6 - fenv\n"); 102143710Sdas test_masking(); 103143710Sdas printf("ok 7 - fenv\n"); 104130330Sdas test_feholdupdate(); 105143710Sdas printf("ok 8 - fenv\n"); 106130330Sdas 107130330Sdas return (0); 108130330Sdas} 109130330Sdas 110130330Sdas/* 111130330Sdas * Initialize std_except_sets[] to the power set of std_excepts[] 112130330Sdas */ 113130330Sdasvoid 114130330Sdasinit_exceptsets(void) 115130330Sdas{ 116130330Sdas int i, j, sr; 117130330Sdas 118130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 119130330Sdas for (sr = i, j = 0; sr != 0; sr >>= 1, j++) 120130330Sdas std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1); 121130330Sdas } 122130330Sdas} 123130330Sdas 124130330Sdas/* 125130330Sdas * This tests checks the default FP environment, so it must be first. 126130330Sdas * The memcmp() test below may be too much to ask for, since there 127130330Sdas * could be multiple machine-specific default environments. 128130330Sdas */ 129130330Sdasstatic void 130130330Sdastest_dfl_env(void) 131130330Sdas{ 132130330Sdas#ifndef NO_STRICT_DFL_ENV 133130330Sdas fenv_t env; 134130330Sdas 135130330Sdas fegetenv(&env); 136130330Sdas assert(memcmp(&env, FE_DFL_ENV, sizeof(env)) == 0); 137130330Sdas#endif 138130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 139130330Sdas} 140130330Sdas 141130330Sdas/* 142130330Sdas * Test fetestexcept() and feclearexcept(). 143130330Sdas */ 144130330Sdasstatic void 145130330Sdastest_fetestclearexcept(void) 146130330Sdas{ 147130330Sdas int excepts, i; 148130330Sdas 149130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) 150130330Sdas assert(fetestexcept(std_except_sets[i]) == 0); 151130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 152130330Sdas excepts = std_except_sets[i]; 153130330Sdas 154130330Sdas /* FE_ALL_EXCEPT might be special-cased, as on i386. */ 155130330Sdas raiseexcept(excepts); 156130330Sdas assert(fetestexcept(excepts) == excepts); 157130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 158130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 159130330Sdas 160130330Sdas raiseexcept(excepts); 161130330Sdas assert(fetestexcept(excepts) == excepts); 162130330Sdas if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 163130330Sdas excepts |= FE_INEXACT; 164130330Sdas assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) == 165130330Sdas excepts); 166130330Sdas } else { 167130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == excepts); 168130330Sdas } 169130330Sdas assert(feclearexcept(excepts) == 0); 170130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 0); 171130330Sdas } 172130330Sdas} 173130330Sdas 174130330Sdas/* 175130330Sdas * Test fegetexceptflag() and fesetexceptflag(). 176130330Sdas * 177130330Sdas * Prerequisites: fetestexcept(), feclearexcept() 178130330Sdas */ 179130330Sdasstatic void 180130330Sdastest_fegsetexceptflag(void) 181130330Sdas{ 182130330Sdas fexcept_t flag; 183130330Sdas int excepts, i; 184130330Sdas 185130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 186130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 187130330Sdas excepts = std_except_sets[i]; 188130330Sdas 189130330Sdas assert(fegetexceptflag(&flag, excepts) == 0); 190130330Sdas raiseexcept(ALL_STD_EXCEPT); 191130330Sdas assert(fesetexceptflag(&flag, excepts) == 0); 192130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 193130330Sdas (ALL_STD_EXCEPT ^ excepts)); 194130330Sdas 195130330Sdas assert(fegetexceptflag(&flag, FE_ALL_EXCEPT) == 0); 196130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 197130330Sdas assert(fesetexceptflag(&flag, excepts) == 0); 198130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 0); 199130330Sdas assert(fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts) == 0); 200130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 201130330Sdas (ALL_STD_EXCEPT ^ excepts)); 202130330Sdas 203130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 204130330Sdas } 205130330Sdas} 206130330Sdas 207130330Sdas/* 208130330Sdas * Test feraiseexcept(). 209130330Sdas * 210130330Sdas * Prerequisites: fetestexcept(), feclearexcept() 211130330Sdas */ 212130330Sdasstatic void 213130330Sdastest_feraiseexcept(void) 214130330Sdas{ 215130330Sdas int excepts, i; 216130330Sdas 217130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 218130330Sdas excepts = std_except_sets[i]; 219130330Sdas 220130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 221130330Sdas assert(feraiseexcept(excepts) == 0); 222130330Sdas if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 223130330Sdas excepts |= FE_INEXACT; 224130330Sdas assert((fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT) == 225130330Sdas excepts); 226130330Sdas } else { 227130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == excepts); 228130330Sdas } 229130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 230130330Sdas } 231130330Sdas assert(feraiseexcept(FE_INVALID | FE_DIVBYZERO) == 0); 232130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == (FE_INVALID | FE_DIVBYZERO)); 233130330Sdas assert(feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) == 0); 234130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == ALL_STD_EXCEPT); 235130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 236130330Sdas} 237130330Sdas 238130330Sdas/* 239130330Sdas * Test fegetround() and fesetround(). 240130330Sdas */ 241130330Sdasstatic void 242130330Sdastest_fegsetround(void) 243130330Sdas{ 244130330Sdas 245130330Sdas assert(fegetround() == FE_TONEAREST); 246130330Sdas assert(getround() == FE_TONEAREST); 247132384Sdas assert(FLT_ROUNDS == 1); 248132384Sdas 249130330Sdas assert(fesetround(FE_DOWNWARD) == 0); 250130330Sdas assert(fegetround() == FE_DOWNWARD); 251130330Sdas assert(getround() == FE_DOWNWARD); 252132384Sdas assert(FLT_ROUNDS == 3); 253132384Sdas 254130330Sdas assert(fesetround(FE_UPWARD) == 0); 255130330Sdas assert(getround() == FE_UPWARD); 256130330Sdas assert(fegetround() == FE_UPWARD); 257132384Sdas assert(FLT_ROUNDS == 2); 258132384Sdas 259130330Sdas assert(fesetround(FE_TOWARDZERO) == 0); 260130330Sdas assert(getround() == FE_TOWARDZERO); 261130330Sdas assert(fegetround() == FE_TOWARDZERO); 262132384Sdas assert(FLT_ROUNDS == 0); 263132384Sdas 264130330Sdas assert(fesetround(FE_TONEAREST) == 0); 265130330Sdas assert(getround() == FE_TONEAREST); 266132384Sdas assert(FLT_ROUNDS == 1); 267132384Sdas 268130330Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); 269130330Sdas} 270130330Sdas 271130330Sdas/* 272130330Sdas * Test fegetenv() and fesetenv(). 273130330Sdas * 274130330Sdas * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() 275130330Sdas */ 276130330Sdasstatic void 277130330Sdastest_fegsetenv(void) 278130330Sdas{ 279130330Sdas fenv_t env1, env2; 280130330Sdas int excepts, i; 281130330Sdas 282130330Sdas for (i = 0; i < 1 << NEXCEPTS; i++) { 283130330Sdas excepts = std_except_sets[i]; 284130330Sdas 285130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 286130330Sdas assert(fegetround() == FE_TONEAREST); 287130330Sdas assert(fegetenv(&env1) == 0); 288130330Sdas 289130330Sdas /* 290130330Sdas * fe[gs]etenv() should be able to save and restore 291130330Sdas * exception flags without the spurious inexact 292130330Sdas * exceptions that afflict raiseexcept(). 293130330Sdas */ 294130330Sdas raiseexcept(excepts); 295130330Sdas if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 && 296130330Sdas (excepts & FE_INEXACT) == 0) 297130330Sdas assert(feclearexcept(FE_INEXACT) == 0); 298130330Sdas 299130330Sdas fesetround(FE_DOWNWARD); 300130330Sdas assert(fegetenv(&env2) == 0); 301130330Sdas assert(fesetenv(&env1) == 0); 302130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 303130330Sdas assert(fegetround() == FE_TONEAREST); 304130330Sdas 305130330Sdas assert(fesetenv(&env2) == 0); 306130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == excepts); 307130330Sdas assert(fegetround() == FE_DOWNWARD); 308130330Sdas assert(fesetenv(&env1) == 0); 309130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 310130330Sdas assert(fegetround() == FE_TONEAREST); 311130330Sdas } 312130330Sdas} 313130330Sdas 314130330Sdas/* 315143710Sdas * Test fegetexcept(), fedisableexcept(), and feenableexcept(). 316130330Sdas * 317130330Sdas * Prerequisites: fetestexcept(), feraiseexcept() 318130330Sdas */ 319130330Sdasstatic void 320143710Sdastest_masking(void) 321130330Sdas{ 322130330Sdas struct sigaction act; 323130330Sdas int except, i, pass, raise, status; 324130330Sdas 325143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == 0); 326143710Sdas assert((feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT) == 0); 327143710Sdas assert((feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT) == 328143710Sdas (FE_INVALID | FE_OVERFLOW)); 329143710Sdas assert((fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT) == 330143710Sdas (FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)); 331143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == (FE_INVALID | FE_UNDERFLOW)); 332143710Sdas assert((fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT) == 333143710Sdas (FE_INVALID | FE_UNDERFLOW)); 334143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == 0); 335143710Sdas 336130330Sdas sigemptyset(&act.sa_mask); 337130330Sdas act.sa_flags = 0; 338130330Sdas act.sa_handler = trap_handler; 339130330Sdas for (pass = 0; pass < 2; pass++) { 340130330Sdas for (i = 0; i < NEXCEPTS; i++) { 341130330Sdas except = std_excepts[i]; 342130330Sdas /* over/underflow may also raise inexact */ 343130330Sdas if (except == FE_INEXACT) 344130330Sdas raise = FE_DIVBYZERO | FE_INVALID; 345130330Sdas else 346130330Sdas raise = ALL_STD_EXCEPT ^ except; 347130330Sdas 348130330Sdas /* 349130330Sdas * We need to fork a child process because 350130330Sdas * there isn't a portable way to recover from 351130330Sdas * a floating-point exception. 352130330Sdas */ 353130330Sdas switch(fork()) { 354130330Sdas case 0: /* child */ 355143710Sdas assert((fegetexcept() & ALL_STD_EXCEPT) == 0); 356143710Sdas assert((feenableexcept(except) 357143710Sdas & ALL_STD_EXCEPT) == 0); 358143710Sdas assert(fegetexcept() == except); 359130330Sdas raiseexcept(raise); 360130330Sdas assert(feraiseexcept(raise) == 0); 361130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == raise); 362130330Sdas 363130330Sdas assert(sigaction(SIGFPE, &act, NULL) == 0); 364130330Sdas switch (pass) { 365130330Sdas case 0: 366130330Sdas raiseexcept(except); 367130330Sdas case 1: 368130330Sdas feraiseexcept(except); 369130330Sdas default: 370130330Sdas assert(0); 371130330Sdas } 372130330Sdas assert(0); 373130330Sdas default: /* parent */ 374130330Sdas assert(wait(&status) > 0); 375130330Sdas /* 376130330Sdas * Avoid assert() here so that it's possible 377130330Sdas * to examine a failed child's core dump. 378130330Sdas */ 379130330Sdas if (!WIFEXITED(status)) 380130330Sdas errx(1, "child aborted\n"); 381130330Sdas assert(WEXITSTATUS(status) == 0); 382130330Sdas break; 383130330Sdas case -1: /* error */ 384130330Sdas assert(0); 385130330Sdas } 386130330Sdas } 387130330Sdas } 388130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 389130330Sdas} 390130330Sdas 391130330Sdas/* 392130330Sdas * Test feholdexcept() and feupdateenv(). 393130330Sdas * 394143710Sdas * Prerequisites: fetestexcept(), fegetround(), fesetround(), 395143710Sdas * fedisableexcept(), feenableexcept() 396130330Sdas */ 397130330Sdasstatic void 398130330Sdastest_feholdupdate(void) 399130330Sdas{ 400130330Sdas fenv_t env; 401130330Sdas 402130330Sdas struct sigaction act; 403130330Sdas int except, i, pass, status, raise; 404130330Sdas 405130330Sdas sigemptyset(&act.sa_mask); 406130330Sdas act.sa_flags = 0; 407130330Sdas act.sa_handler = trap_handler; 408130330Sdas for (pass = 0; pass < 2; pass++) { 409130330Sdas for (i = 0; i < NEXCEPTS; i++) { 410130330Sdas except = std_excepts[i]; 411130330Sdas /* over/underflow may also raise inexact */ 412130330Sdas if (except == FE_INEXACT) 413130330Sdas raise = FE_DIVBYZERO | FE_INVALID; 414130330Sdas else 415130330Sdas raise = ALL_STD_EXCEPT ^ except; 416130330Sdas 417130330Sdas /* 418130330Sdas * We need to fork a child process because 419130330Sdas * there isn't a portable way to recover from 420130330Sdas * a floating-point exception. 421130330Sdas */ 422130330Sdas switch(fork()) { 423130330Sdas case 0: /* child */ 424130330Sdas /* 425130330Sdas * We don't want to cause a fatal exception in 426130330Sdas * the child until the second pass, so we can 427130330Sdas * check other properties of feupdateenv(). 428130330Sdas */ 429130330Sdas if (pass == 1) 430143710Sdas assert((feenableexcept(except) & 431130330Sdas ALL_STD_EXCEPT) == 0); 432130330Sdas raiseexcept(raise); 433130330Sdas assert(fesetround(FE_DOWNWARD) == 0); 434130330Sdas assert(feholdexcept(&env) == 0); 435130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 436130330Sdas raiseexcept(except); 437130330Sdas assert(fesetround(FE_UPWARD) == 0); 438130330Sdas 439130330Sdas if (pass == 1) 440130330Sdas assert(sigaction(SIGFPE, &act, NULL) == 441130330Sdas 0); 442130330Sdas assert(feupdateenv(&env) == 0); 443130330Sdas assert(fegetround() == FE_DOWNWARD); 444130330Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 445130330Sdas (except | raise)); 446130330Sdas 447130330Sdas assert(pass == 0); 448130330Sdas _exit(0); 449130330Sdas default: /* parent */ 450130330Sdas assert(wait(&status) > 0); 451130330Sdas /* 452130330Sdas * Avoid assert() here so that it's possible 453130330Sdas * to examine a failed child's core dump. 454130330Sdas */ 455130330Sdas if (!WIFEXITED(status)) 456130330Sdas errx(1, "child aborted\n"); 457130330Sdas assert(WEXITSTATUS(status) == 0); 458130330Sdas break; 459130330Sdas case -1: /* error */ 460130330Sdas assert(0); 461130330Sdas } 462130330Sdas } 463130330Sdas } 464130330Sdas assert(fetestexcept(FE_ALL_EXCEPT) == 0); 465130330Sdas} 466130330Sdas 467130330Sdas/* 468130330Sdas * Raise a floating-point exception without relying on the standard 469130330Sdas * library routines, which we are trying to test. 470130330Sdas * 471130330Sdas * XXX We can't raise an {over,under}flow without also raising an 472130330Sdas * inexact exception. 473130330Sdas */ 474130330Sdasstatic void 475130330Sdasraiseexcept(int excepts) 476130330Sdas{ 477130330Sdas volatile double d; 478130330Sdas 479130330Sdas /* 480130330Sdas * With a compiler that supports the FENV_ACCESS pragma 481130330Sdas * properly, simple expressions like '0.0 / 0.0' should 482130330Sdas * be sufficient to generate traps. Unfortunately, we 483130330Sdas * need to bring a volatile variable into the equation 484130330Sdas * to prevent incorrect optimizations. 485130330Sdas */ 486130330Sdas if (excepts & FE_INVALID) { 487130330Sdas d = 0.0; 488130330Sdas d = 0.0 / d; 489130330Sdas } 490130330Sdas if (excepts & FE_DIVBYZERO) { 491130330Sdas d = 0.0; 492130330Sdas d = 1.0 / d; 493130330Sdas } 494130330Sdas if (excepts & FE_OVERFLOW) { 495130330Sdas d = DBL_MAX; 496130330Sdas d *= 2.0; 497130330Sdas } 498130330Sdas if (excepts & FE_UNDERFLOW) { 499130330Sdas d = DBL_MIN; 500130330Sdas d /= DBL_MAX; 501130330Sdas } 502130330Sdas if (excepts & FE_INEXACT) { 503130330Sdas d = DBL_MIN; 504130330Sdas d += 1.0; 505130330Sdas } 506130330Sdas 507130330Sdas /* 508130330Sdas * On the x86 (and some other architectures?) the FPU and 509130330Sdas * integer units are decoupled. We need to execute an FWAIT 510130330Sdas * or a floating-point instruction to get synchronous exceptions. 511130330Sdas */ 512130330Sdas d = 1.0; 513130330Sdas d += 1.0; 514130330Sdas} 515130330Sdas 516130330Sdas/* 517130330Sdas * Determine the current rounding mode without relying on the fenv 518130330Sdas * routines. This function may raise an inexact exception. 519130330Sdas */ 520130330Sdasstatic int 521130330Sdasgetround(void) 522130330Sdas{ 523130330Sdas volatile double d; 524130330Sdas 525130330Sdas /* 526130330Sdas * This test works just as well with 0.0 - 0.0, except on ia64 527130330Sdas * where 0.0 - 0.0 gives the wrong sign when rounding downwards. 528130330Sdas */ 529130330Sdas d = 1.0; 530130330Sdas d -= 1.0; 531130330Sdas if (copysign(1.0, d) < 0.0) 532130330Sdas return (FE_DOWNWARD); 533130330Sdas 534130330Sdas d = 1.0; 535130330Sdas if (d + (DBL_EPSILON * 3.0 / 4.0) == 1.0) 536130330Sdas return (FE_TOWARDZERO); 537130330Sdas if (d + (DBL_EPSILON * 1.0 / 4.0) > 1.0) 538130330Sdas return (FE_UPWARD); 539130330Sdas 540130330Sdas return (FE_TONEAREST); 541130330Sdas} 542130330Sdas 543130330Sdasstatic void 544130330Sdastrap_handler(int sig) 545130330Sdas{ 546130330Sdas 547130330Sdas assert(sig == SIGFPE); 548130330Sdas _exit(0); 549130330Sdas} 550