Can I make gcc tell me when a calculation results in NaN or inf at runtime?
Is there a way to tell gcc to throw a SIGFPE or something similar in response to a calculation that results in NaN
or (-)inf
at runtime, like it would for a divide-by-zero?
I've tried the -fsignaling-nans
flag, which doesn't seem to help.
Solution 1:
Almost any floating-point operation or math library function that produces a NaN from non-NaN inputs should also signal the 'invalid operation' floating-point exception; similarly, a calculation that produces an infinity from finite inputs will typically signal either the 'divide-by-zero' or 'overflow' floating-point exception. So you want some way of turning these exceptions into a SIGFPE.
I suspect the answer will be highly system-dependent, since control of floating-point traps and flags is likely to be supplied by the platform C library rather than by gcc itself. But here's an example that works for me, on Linux. It uses the feenableexcept
function from fenv.h
. The _GNU_SOURCE
define is necessary for this function to be declared.
#define _GNU_SOURCE
#include <fenv.h>
int main(void) {
double x, y, z;
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
x = 1e300;
y = 1e300;
z = x * y; /* should cause an FPE */
return 0;
}
A caveat: I think it's possible with some setups that the exception isn't actually generated until the next floating-point operation after the one that (in theory) should have caused it, so you sometimes need a no-op floating-point operation (e.g. multiplying by 1.0) to trigger the exception.
Solution 2:
On MinGW 4.8.1 (GCC for Win32) I see that the feenableexcept
isn't defined. The workaround is to use the Win32 platform's _controlfp
thus:
#undef __STRICT_ANSI__ // _controlfp is a non-standard function documented in MSDN
#include <float.h>
#include <stdio.h>
int main()
{
_clearfp();
unsigned unused_current_word = 0;
// clearing the bits unmasks (throws) the exception
_controlfp_s(&unused_current_word, 0, _EM_OVERFLOW | _EM_ZERODIVIDE); // _controlfp_s is the secure version of _controlfp
float num = 1.0f, den = 0.0f;
float quo = num / den;
printf("%.8f\n", quo); // the control should never reach here, due to the exception thrown above
}