tests for fenv.h, improv

This commit is contained in:
bumbread 2022-06-10 18:38:32 +11:00
parent 2cc1ad7504
commit caef55ef67
3 changed files with 67 additions and 6 deletions

View File

@ -4,6 +4,7 @@
#define fe_masks(excepts) (((fexcept_t)(excepts)) << 7) #define fe_masks(excepts) (((fexcept_t)(excepts)) << 7)
#define fe_flags(excepts) ((fexcept_t)(excepts)) #define fe_flags(excepts) ((fexcept_t)(excepts))
#define fe_excepts(masks) ((int)(masks >> 7))
fenv_t _fe_dfl_env = 0x1f80; // Based (on my machine) fenv_t _fe_dfl_env = 0x1f80; // Based (on my machine)
@ -16,7 +17,7 @@ int feclearexcept(int excepts)
return 0; return 0;
} }
fexcept_t csr = _mm_getcsr(); fexcept_t csr = _mm_getcsr();
csr |= fe_masks(excepts); csr &= ~fe_flags(excepts);
_mm_setcsr(csr); _mm_setcsr(csr);
return 0; return 0;
} }

View File

@ -9,12 +9,18 @@ typedef unsigned fenv_t;
#define FE_OVERFLOW (1 << 3) #define FE_OVERFLOW (1 << 3)
#define FE_UNDERFLOW (1 << 4) #define FE_UNDERFLOW (1 << 4)
#define FE_INEXACT (1 << 5) #define FE_INEXACT (1 << 5)
// Implementation-defined flags
#define FE_DENORM (1 << 1)
#define FE_DAZ (1 << 6)
#define FE_ALL_EXCEPT \ #define FE_ALL_EXCEPT \
( FE_INVALID \ ( FE_INVALID \
| FE_DIVBYZERO \ | FE_DIVBYZERO \
| FE_OVERFLOW \ | FE_OVERFLOW \
| FE_UNDERFLOW \ | FE_UNDERFLOW \
| FE_INEXACT ) | FE_INEXACT \
| FE_DENORM \
| FE_DAZ )
#define FE_TONEAREST 0x00 #define FE_TONEAREST 0x00
#define FE_DOWNWARD 0x01 #define FE_DOWNWARD 0x01

View File

@ -1,6 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include <fenv.h> #include <fenv.h>
#include <float.h>
#include <emmintrin.h> #include <emmintrin.h>
@ -10,6 +11,18 @@ static inline double rint (double const x) {
return (double)_mm_cvtsd_si32(_mm_load_sd(&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) void show_fe_current_rounding_direction(void)
{ {
printf("current rounding direction: "); printf("current rounding direction: ");
@ -22,26 +35,67 @@ void show_fe_current_rounding_direction(void)
}; };
printf("\n"); 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) int main(void)
{ {
// ROUNDING MODES
printf("\nROUNDING MODES\n");
/* Default rounding direction */ /* Default rounding direction */
show_fe_current_rounding_direction(); show_fe_current_rounding_direction();
printf("+11.5 -> %f\n", rint(+11.5)); /* midway between two integers */ printf("+11.5 -> %f\n", rint(+11.5)); /* midway between two integers */
printf("+12.5 -> %f\n", rint(+12.5)); /* midway between two integers */ printf("+12.5 -> %f\n", rint(+12.5)); /* midway between two integers */
/* Save current rounding direction. */ /* Save current rounding direction. */
int curr_direction = fegetround(); int curr_direction = fegetround();
/* Temporarily change current rounding direction. */ /* Temporarily change current rounding direction. */
fesetround(FE_DOWNWARD); fesetround(FE_DOWNWARD);
show_fe_current_rounding_direction(); show_fe_current_rounding_direction();
printf("+11.5 -> %f\n", rint(+11.5)); printf("+11.5 -> %f\n", rint(+11.5));
printf("+12.5 -> %f\n", rint(+12.5)); printf("+12.5 -> %f\n", rint(+12.5));
/* Restore default rounding direction. */ /* Restore default rounding direction. */
fesetround(curr_direction); fesetround(curr_direction);
show_fe_current_rounding_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; return 0;
} }