How to Make a Portable Isnan/Isinf Function

A portable check for infinity and not-a-number

Confident OP's code does not always work.

A double (e.g. IEEE 754) has a non-unique NaN binary representation of:

(s is the sign bit.)

s1111111 1111baaa How to Make a Portable Isnan/Isinf Function How to Make a Portable Isnan/Isinf Function How to Make a Portable Isnan/Isinf Function How to Make a Portable Isnan/Isinf Function How to Make a Portable Isnan/Isinf Function How to Make a Portable Isnan/Isinf Function

Where not all baa ... aaa is 0. (if baa ... aaa is all 0, then it is INF.) The difference between quiet NaN and signaling NaN is often signified with the value of b.

The salient issue is that not all NaN have the same bit pattern. The testing proposed for double against a single bit pattern is an insufficient test for NaN detection.

Suggest instead a portable test that does not rely on NaN, nor Infinity existing in a given C's platform.

double x;

// NAN are never arithmetically equal, even to themselves.
if (x != x) NaN_Detected();
if (x > DBL_MAX || x < -DBL_MAX) Inf_Detected();

[Edit] compare fix: thanks to @Jongware

Is it possible to make isnan() work in gfortran -O3 -ffast-math?

First I would point out that gfortran 4.9 supports the IEEE_arithmetic module. However, the checks in the procedures in that module can be optimized away and the same logic applies.

However, I could not depend GCC 4.9in 2014, it was too fresh. I used the following.

When I had to use x/=x I moved the check x/=x to a procedure which is compiled without -ffast-math and without link time optimizations:

module my_is_nan_mod
!poor man's replacement for the intrinsic module
!do not use if the compiler supports the F2003 version
!make sure not to use fast math optimizations when compiling
use iso_fortran_env

!the common extension isnan() may actually fail with fast math optimizations


interface my_is_nan
module procedure my_is_nan_real32
module procedure my_is_nan_real64
end interface

contains
logical function my_is_nan_real32(x) result(res)
real(real32), intent(in) :: x

res = x /= x
end function

logical elemental function my_is_nan_real64(x) result(res)
real(real64), intent(in) :: x

res = x /= x
end function

end module

It is in a separate file, which is then compiled without -Ofast, --ffast-math and without -flto. Beware the lack of inlining can cause serious performance decrease.

With -ffast-math the compiler sees x/=x, decides that it cannot ever be true and optimizes the expression to just .false..

Why is isnan ambiguous and how to avoid it?

This is a libstdc++ bug documented in the bug report std functions conflicts with C functions when building with c++0x support (and using namespace std) with a reproducing sample very similar to the OP's:

#include <stdlib.h>
#include <cmath>
#include <stdio.h>

using namespace std;

int main(int argc, char** argv)
{
double number = 0;
if (isnan(number))
{
printf("Nan\n");
}
return 0;
}

and one of the comments says:

I don't think that's the problem, because libstdc++ has always declared the names in the global namespace even though it wasn't valid in C++03 - we haven't changed that for C++0x (all that happened is the standard was relaxed to reflect the reality of actual implementations)

This may eventually get fixed until then the solution provided from the bug report is as follows:

Qualify isnan explicitly, by calling either ::isnan or std::isnan

Using ::isnan as far as I can tell works pre C++11 and in C++11.

Of course this is a libstdc++ specific solution, it looks valid in libc++ as well but if you need to support a compiler where this does not work you will probably have to resort to using #if/#else.

Note, as indicated by M.M having isnan marked constexpr is non-conforming, this is a known issue as well although it does not contribute to this particular issue.

Also see related bug reports: [C++11] call of overloaded ‘isnan’ is ambiguous and Recognize builtins with bool return type. The second discusses possible libstdc++ solutions.

Update

If you want a gcc/clang solution it looks like they both support __builtin_isnan, see gcc docs on builtins for more information. Also see this glibc bug report on replacing isnan et al with the builtin.

using an if statement to switch nan values in an array to 0.0?

From what I remember, in every language, NaN will compare false to everything, including itself. You can use this behavior to weed it out:

if( angle[i] != angle[i] ) { angle[i] = 0.0 };

This looks like C, C++, or Java; in all of these, this trick should work.

How to use nan and inf in C?

You can test if your implementation has it:

#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif

The existence of INFINITY is guaranteed by C99 (or the latest draft at least), and "expands to a constant expression of type float representing positive or unsigned
infinity, if available; else to a positive constant of type float that overflows at translation time."

NAN may or may not be defined, and "is defined if and only if the implementation supports quiet NaNs for the float type. It expands to a constant expression of type float representing a quiet NaN."

Note that if you're comparing floating point values, and do:

a = NAN;

even then,

a == NAN;

is false. One way to check for NaN would be:

#include <math.h>
if (isnan(a)) { ... }

You can also do: a != a to test if a is NaN.

There is also isfinite(), isinf(), isnormal(), and signbit() macros in math.h in C99.

C99 also has nan functions:

#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);

(Reference: n1256).

Docs INFINITY
Docs NAN

Check if a number is +-Inf or NaN

C99 has macros for the classification of floating-point numbers:

fpclassify(x) returns one of:

  • FP_NAN: x is not a number;
  • FP_INFINITE: x is plus or minus infinite;
  • FP_ZERO: x is zero;
  • FP_SUBNORMAL: x is too small to be represented in normalized format or
  • FP_NORMAL: normal floating-point number, i.e. none of the above.

There are also shortcuts that check for one of these classes, which return non-zero if x is what :

   isfinite(x)
isnormal(x)
isnan(x)
isinf(x)

The argument x can be any floating-point expression; the macros detect the type of the argument and work for float and double.

EDIT: Since you don't want to use (or cannot use) <math.h>, you could use other properties of nan and inf to classify your numers:

  • nan compares false to all numbers, including to itself;
  • inf is greater than FLT_MAX;
  • -inf is smaller than -FLT_MAX.

So:

#include <stdlib.h>
#include <stdio.h>
#include <float.h>

int main()
{
float f[] = {
0.0, 1.0, FLT_MAX, 0.0 / 0.0, 1.0/0.0, -1.0/0.0
};
int i;

for (i = 0; i < 6; i++) {
float x = f[i];

int is_nan = (x != x);
int is_inf = (x < -FLT_MAX || x > FLT_MAX);

printf("%20g%4d%4d\n", x, is_nan, is_inf);
}

return 0;
}

In this solution, you must adapt the limits if you want to use double.

Checking if a double (or float) is NaN in C++

According to the IEEE standard, NaN values have the odd property that comparisons involving them are always false. That is, for a float f, f != f will be true only if f is NaN.

Note that, as some comments below have pointed out, not all compilers respect this when optimizing code.

For any compiler which claims to use IEEE floating point, this trick should work. But I can't guarantee that it will work in practice. Check with your compiler, if in doubt.



Related Topics



Leave a reply



Submit