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 orFP_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 thanFLT_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
C++: When (And How) Are C++ Global Static Constructors Called
Populate an Array Using Constexpr at Compile-Time
How to Read Groups of Integers from a File, Line by Line in C++
Making a Template Parameter a Friend
Why Do We Need to Use 'Int Main' and Not 'Void Main' in C++
Dynamically Allocated Memory After Program Termination
Prefix/Postfix Increment Operators
How to Access Private Data Members Outside the Class Without Making "Friend"S
How to Automatically Register a Class on Creation
Std::Unique_Ptr for C Functions That Need Free
When Is a Function Try Block Useful
Class Template Argument Deduction Not Working with Alias Template
Should a Move Constructor Take a Const or Non-Const Rvalue Reference
How to Use an Array as Map Value