diff --git a/code/fenv.c b/code/fenv.c index 03e11b2..dfbd6ec 100644 --- a/code/fenv.c +++ b/code/fenv.c @@ -4,6 +4,7 @@ #define fe_masks(excepts) (((fexcept_t)(excepts)) << 7) #define fe_flags(excepts) ((fexcept_t)(excepts)) +#define fe_excepts(masks) ((int)(masks >> 7)) fenv_t _fe_dfl_env = 0x1f80; // Based (on my machine) @@ -16,7 +17,7 @@ int feclearexcept(int excepts) return 0; } fexcept_t csr = _mm_getcsr(); - csr |= fe_masks(excepts); + csr &= ~fe_flags(excepts); _mm_setcsr(csr); return 0; } diff --git a/inc/fenv.h b/inc/fenv.h index a852545..bd49803 100644 --- a/inc/fenv.h +++ b/inc/fenv.h @@ -9,12 +9,18 @@ typedef unsigned fenv_t; #define FE_OVERFLOW (1 << 3) #define FE_UNDERFLOW (1 << 4) #define FE_INEXACT (1 << 5) +// Implementation-defined flags +#define FE_DENORM (1 << 1) +#define FE_DAZ (1 << 6) + #define FE_ALL_EXCEPT \ ( FE_INVALID \ | FE_DIVBYZERO \ | FE_OVERFLOW \ | FE_UNDERFLOW \ - | FE_INEXACT ) + | FE_INEXACT \ + | FE_DENORM \ + | FE_DAZ ) #define FE_TONEAREST 0x00 #define FE_DOWNWARD 0x01 diff --git a/test/test6.c b/test/test6.c index 3d7e624..b1a2743 100644 --- a/test/test6.c +++ b/test/test6.c @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -10,6 +11,18 @@ static inline double rint (double const x) { return (double)_mm_cvtsd_si32(_mm_load_sd(&x)); } +void show_fe_exceptions(void) +{ + printf("current exceptions raised: "); + if(fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO"); + if(fetestexcept(FE_INEXACT)) printf(" FE_INEXACT"); + if(fetestexcept(FE_INVALID)) printf(" FE_INVALID"); + if(fetestexcept(FE_OVERFLOW)) printf(" FE_OVERFLOW"); + if(fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW"); + if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none"); + printf("\n"); +} + void show_fe_current_rounding_direction(void) { printf("current rounding direction: "); @@ -22,26 +35,67 @@ void show_fe_current_rounding_direction(void) }; printf("\n"); } + +double x2 (double x) /* times two */ +{ + fenv_t curr_excepts; + /* Save and clear current f-p environment. */ + feholdexcept(&curr_excepts); + + /* Raise inexact and overflow exceptions. */ + printf("In x2(): x = %f\n", x=x*2.0); + show_fe_exceptions(); + feclearexcept(FE_INEXACT); /* hide inexact exception from caller */ + + /* Merge caller's exceptions (FE_INVALID) */ + /* with remaining x2's exceptions (FE_OVERFLOW). */ + feupdateenv(&curr_excepts); + return x; +} + + int main(void) { + // ROUNDING MODES + printf("\nROUNDING MODES\n"); /* Default rounding direction */ show_fe_current_rounding_direction(); printf("+11.5 -> %f\n", rint(+11.5)); /* midway between two integers */ printf("+12.5 -> %f\n", rint(+12.5)); /* midway between two integers */ - + /* Save current rounding direction. */ int curr_direction = fegetround(); - + /* Temporarily change current rounding direction. */ fesetround(FE_DOWNWARD); show_fe_current_rounding_direction(); printf("+11.5 -> %f\n", rint(+11.5)); printf("+12.5 -> %f\n", rint(+12.5)); - + /* Restore default rounding direction. */ fesetround(curr_direction); show_fe_current_rounding_direction(); - + + // EXCEPTION TEST + printf("\nEXCEPTIONS\n"); + + show_fe_exceptions(); + + /* Perform some computations which raise exceptions. */ + printf("1.0/0.0 = %f\n", 1.0/0.0); /* FE_DIVBYZERO */ + printf("1.0/10.0 = %f\n", 1.0/10.0); /* FE_INEXACT */ + printf("DBL_MAX*2.0 = %f\n", DBL_MAX*2.0); /* FE_INEXACT FE_OVERFLOW */ + show_fe_exceptions(); + + // FEHOLDEXCEPT + printf("\nFEHOLDEXCEPT\n"); + + feclearexcept(FE_ALL_EXCEPT); + feraiseexcept(FE_INVALID); /* some computation with invalid argument */ + show_fe_exceptions(); + printf("x2(DBL_MAX) = %f\n", x2(DBL_MAX)); + show_fe_exceptions(); + return 0; }