Reputation: 3184
In a numerical application, I'd like to know if a floating point exception occured after the computation finishes. By default, floating point divisions and invalid operations are ignored silently.
My attempt is to enable FPEs I care about, handle SIGFPE by setting a flag and disabling them again to allow execution to continue:
#include <fenv.h>
#include <signal.h>
#include <stdio.h>
int caught = 0;
struct sigaction old_sa;
/* (2) */ fenv_t fenv_hold;
void sighandler()
{
caught = 1;
printf("Caught in handler, disabling\n");
/* (1) */ fedisableexcept(FE_ALL_EXCEPT);
/* (2) */ feholdexcept(&fenv_hold);
sigaction(SIGFPE, &old_sa, NULL);
}
int main(void)
{
struct sigaction sa;
volatile double a=1, b=0;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sighandler;
sigaction(SIGFPE, &sa, &old_sa);
feenableexcept(FE_DIVBYZERO);
printf("Dividing by zero..\n");
a/=b;
printf("Continuing\n");
}
I took two approaches, the first one labeled with (1)
, the second one with (2)
. Neither of them works as expected.
Output:
Dividing by zero..
Caught in handler, disabling
Floating point exception (core dumped)
Expected Output:
Dividing by zero..
Caught in handler, disabling
Continuing
Upvotes: 3
Views: 1398
Reputation: 222923
If you just want to know, after a computation finishes, whether a floating-point exception occurred, then you should not use signals, as they have a high overhead. Instead, use the floating-point exception flags, which are set quickly by the processor during normal execution. (However, accessing them may have some performance effect.)
See the C standard on <fenv.h>
. Briefly:
#include <fenv.h>
in your source file.#pragma STDC FENV_ACCESS on
before any source code that might access the floating-point flags or run under non-default floating-point modes.#pragma STDC FENV_ACCESS off
after the above source code, when the following source code does not access the flags or run under non-default modes.feclearexcept(FE_ALL_EXCEPT)
to clear flags.fetestexcept(exceptions)
to test flags. exceptions
should be a bitwise OR of FE_DIVBYZERO
, FE_INEXACT
, FE_INVALID
, FE_OVERFLOW
, and/or FE_UNDERFLOW
, and possibly additional implementation-defined flags.Note that some C implementations have poor support for accessing the floating-point environment.
Upvotes: 7