Znajdujemy plik ( Ubuntu) :

locate fenv.h


Wybieramy plik


/usr/include/fenv.h

który odsyła nas do pliku :

/usr/include/x86_64-linux-gnu/bits/fenv.h

Definicje

edytuj
/* Define bits representing the exception.  We use the bit positions
   of the appropriate bits in the FPU control word.  */
enum
  {
    FE_INVALID =
#define FE_INVALID	0x01
      FE_INVALID,
    __FE_DENORM = 0x02,
    FE_DIVBYZERO =
#define FE_DIVBYZERO	0x04
      FE_DIVBYZERO,
    FE_OVERFLOW =
#define FE_OVERFLOW	0x08
      FE_OVERFLOW,
    FE_UNDERFLOW =
#define FE_UNDERFLOW	0x10
      FE_UNDERFLOW,
    FE_INEXACT =
#define FE_INEXACT	0x20
      FE_INEXACT
  };

#define FE_ALL_EXCEPT \
	(FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)

Makra i ich opisy [1]:

/*
   FE_INEXACT		inexact result :  An inexact floating-point exception can occur when a finite floating-point result cannot be exactly represented, as in 2.0 / 3.0
   FE_DIVBYZERO		division by zero : A zero-divide floating-point exception can occur when a floating-point divide has a finite dividend and a zero divisor, as in 1.0 / 0.0.
   FE_UNDERFLOW		result not representable due to underflow : An overflow floating-point exception can occur when the magnitude of a finite floating-point result is too large to represent, as in DBL_MAX / DBL_MIN
   FE_OVERFLOW		result not representable due to overflow : An underflow floating-point exception can occur when the magnitude of a finite floating-point result is too small to represent, as in DBL_MIN / DBL_MAX
   FE_INVALID		invalid operation : An invalid floating-point exception can occur when a floating-point operation involves an invalid combination of operators and operands, as in 0.0 / 0.0
   FE_ALL_EXCEPT	bitwise OR of all supported exceptions

*/

Użycie

edytuj
  • #include <fenv.h>
  • -lm



Przykłady

edytuj


feenableexcept

edytuj
/// c99 t.c -lm -Wall
// http://jayconrod.com/posts/33/trapping-floating-point-exceptions-in-linux#define _GNU_SOURCE
#include <fenv.h>

int main(void) {
    feenableexcept(FE_INVALID   | 
                   FE_DIVBYZERO | 
                   FE_OVERFLOW  | 
                   FE_UNDERFLOW);
    float a = 1., b = 0.;
    float c = a/b;
    return 0;
}

Uruchamiamy :

./a.out

Wynik :

Błąd w obliczeniach zmiennoprzecinkowych


fetestexcept

edytuj
// http://en.cppreference.com/w/c/numeric/fenv/FE_exceptions

// gcc t.c -Wall -std=c99 -lm -frounding-math
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>


void show_fe_exceptions(void)
{
    printf("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");
    feclearexcept(FE_ALL_EXCEPT);
    printf("\n");
}
 
int main(void)
{
    printf("MATH_ERREXCEPT is %s\n",
           math_errhandling & MATH_ERREXCEPT ? "set" : "not set");
 
    printf("0.0/0.0 = %f\n", 0.0/0.0);
    show_fe_exceptions();
 
    printf("1.0/0.0 = %f\n", 1.0/0.0);
    show_fe_exceptions();
 
    printf("1.0/10.0 = %f\n", 1.0/10.0);
    show_fe_exceptions();
 
    printf("sqrt(-1) = %f\n", sqrt(-1));
    show_fe_exceptions();
 
    printf("DBL_MAX*2.0 = %f\n", DBL_MAX*2.0);
    show_fe_exceptions();
 
    printf("nextafter(DBL_MIN/pow(2.0,52),0.0) = %.1f\n",
                      nextafter(DBL_MIN/pow(2.0,52),0.0));
    show_fe_exceptions();
}

Kompilujemy


 gcc -std=c99 t.c -Wall  -lm 

uruchamiamy :

./a.out

Wynik :

MATH_ERREXCEPT is set
0.0/0.0 = -nan
exceptions raised: FE_INVALID
1.0/0.0 = inf
exceptions raised: FE_DIVBYZERO
1.0/10.0 = 0.100000
exceptions raised:
sqrt(-1) = -nan
exceptions raised: FE_INVALID
DBL_MAX*2.0 = inf
exceptions raised: FE_INEXACT FE_OVERFLOW
nextafter(DBL_MIN/pow(2.0,52),0.0) = 0.0
exceptions raised: FE_INEXACT FE_UNDERFLOW

Źródła

edytuj
  1. Dinkum C and C++ Libraries buy P.J. Plauger 1989-2002
  2. musl is a C standard library implementation for Linux.