Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 711
Jordan Lewis Avatar asked May 31 '10 05:05

Jordan Lewis


People also ask

How to check if a value is NaN in C?

NaN is unordered: it is not equal to, greater than, or less than anything, including itself. x == x is false if the value of x is NaN. You can use this to test whether a value is NaN or not, but the recommended way to test for NaN is with the isnan function (see Floating-Point Number Classification Functions).

How to define NaN in C?

In computing, NaN (/næn/), standing for Not a Number, is a member of a numeric data type that can be interpreted as a value that is undefined or unrepresentable, especially in floating-point arithmetic.

What does NaN mean in coding?

Easily the strangest thing about floating-point numbers is the floating-point value “NaN”. Short for “Not a Number”, even its name is a paradox. Only floating-point values can be NaN, meaning that from a type-system point of view, only numbers can be “not a number”.


2 Answers

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.

like image 51
Mark Dickinson Avatar answered Oct 20 '22 05:10

Mark Dickinson


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
}
like image 39
legends2k Avatar answered Oct 20 '22 05:10

legends2k