Related
Is there an isnan() function?
PS.: I'm in MinGW (if that makes a difference).
I had this solved by using isnan() from <math.h>, which doesn't exist in <cmath>, which I was #includeing at first.
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.
There is no isnan() function available in current C++ Standard Library. It was introduced in C99 and defined as a macro not a function. Elements of standard library defined by C99 are not part of current C++ standard ISO/IEC 14882:1998 neither its update ISO/IEC 14882:2003.
In 2005 Technical Report 1 was proposed. The TR1 brings compatibility with C99 to C++. In spite of the fact it has never been officially adopted to become C++ standard, many (GCC 4.0+ or Visual C++ 9.0+ C++ implementations do provide TR1 features, all of them or only some (Visual C++ 9.0 does not provide C99 math functions).
If TR1 is available, then cmath includes C99 elements like isnan(), isfinite(), etc. but they are defined as functions, not macros, usually in std::tr1:: namespace, though many implementations (i.e. GCC 4+ on Linux or in XCode on Mac OS X 10.5+) inject them directly to std::, so std::isnan is well defined.
Moreover, some implementations of C++ still make C99 isnan() macro available for C++ (included through cmath or math.h), what may cause more confusions and developers may assume it's a standard behaviour.
A note about Viusal C++, as mentioned above, it does not provide std::isnan neither std::tr1::isnan, but it provides an extension function defined as _isnan() which has been available since Visual C++ 6.0
On XCode, there is even more fun. As mentioned, GCC 4+ defines std::isnan. For older versions of compiler and library form XCode, it seems (here is relevant discussion), haven't had chance to check myself) two functions are defined, __inline_isnand() on Intel and __isnand() on Power PC.
First solution: if you are using C++11
Since this was asked there were a bit of new developments: it is important to know that std::isnan() is part of C++11
Synopsis
Defined in header <cmath>
bool isnan( float arg ); (since C++11)
bool isnan( double arg ); (since C++11)
bool isnan( long double arg ); (since C++11)
Determines if the given floating point number arg is not-a-number (NaN).
Parameters
arg: floating point value
Return value
true if arg is NaN, false otherwise
Reference
http://en.cppreference.com/w/cpp/numeric/math/isnan
Please note that this is incompatible with -fast-math if you use g++, see below for other suggestions.
Other solutions: if you using non C++11 compliant tools
For C99, in C, this is implemented as a macro isnan(c)that returns an int value. The type of x shall be float, double or long double.
Various vendors may or may not include or not a function isnan().
The supposedly portable way to check for NaN is to use the IEEE 754 property that NaN is not equal to itself: i.e. x == x will be false for x being NaN.
However the last option may not work with every compiler and some settings (particularly optimisation settings), so in last resort, you can always check the bit pattern ...
There is also a header-only library present in Boost that have neat tools to deal with floating point datatypes
#include <boost/math/special_functions/fpclassify.hpp>
You get the following functions:
template <class T> bool isfinite(T z);
template <class T> bool isinf(T t);
template <class T> bool isnan(T t);
template <class T> bool isnormal(T t);
If you have time then have a look at whole Math toolkit from Boost, it has many useful tools and is growing quickly.
Also when dealing with floating and non-floating points it might be a good idea to look at the Numeric Conversions.
There are three "official" ways: posix isnan macro, c++0x isnan function template, or visual c++ _isnan function.
Unfortunately it's rather impractical to detect which of those to use.
And unfortunately, there's no reliable way to detect whether you have IEEE 754 representation with NaNs. The standard library offers an official such way (numeric_limits<double>::is_iec559). But in practice compilers such as g++ screw that up.
In theory one could use simply x != x, but compilers such as g++ and visual c++ screw that up.
So in the end, test for the specific NaN bitpatterns, assuming (and hopefully enforcing, at some point!) a particular representation such as IEEE 754.
EDIT: as an example of "compilers such as g++ … screw that up", consider
#include <limits>
#include <assert.h>
void foo( double a, double b )
{
assert( a != b );
}
int main()
{
typedef std::numeric_limits<double> Info;
double const nan1 = Info::quiet_NaN();
double const nan2 = Info::quiet_NaN();
foo( nan1, nan2 );
}
Compiling with g++ (TDM-2 mingw32) 4.4.1:
C:\test> type "C:\Program Files\#commands\gnuc.bat"
#rem -finput-charset=windows-1252
#g++ -O -pedantic -std=c++98 -Wall -Wwrite-strings %* -Wno-long-long
C:\test> gnuc x.cpp
C:\test> a && echo works... || echo !failed
works...
C:\test> gnuc x.cpp --fast-math
C:\test> a && echo works... || echo !failed
Assertion failed: a != b, file x.cpp, line 6
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
!failed
C:\test> _
There is an std::isnan if you compiler supports c99 extensions, but I'm not sure if mingw does.
Here is a small function which should work if your compiler doesn't have the standard function:
bool custom_isnan(double var)
{
volatile double d = var;
return d != d;
}
You can use numeric_limits<float>::quiet_NaN( ) defined in the limits standard library to test with. There's a separate constant defined for double.
#include <iostream>
#include <math.h>
#include <limits>
using namespace std;
int main( )
{
cout << "The quiet NaN for type float is: "
<< numeric_limits<float>::quiet_NaN( )
<< endl;
float f_nan = numeric_limits<float>::quiet_NaN();
if( isnan(f_nan) )
{
cout << "Float was Not a Number: " << f_nan << endl;
}
return 0;
}
I don't know if this works on all platforms, as I only tested with g++ on Linux.
You can use the isnan() function, but you need to include the C math library.
#include <cmath>
As this function is part of C99, it is not available everywhere. If your vendor does not supply the function, you can also define your own variant for compatibility.
inline bool isnan(double x) {
return x != x;
}
As of C++14 there are a number of ways to test if a floating point number value is a NaN.
Of these ways, only checking of the bits of the number's representation,
works reliably, as noted in my original answer. In particular, std::isnan and the often proposed check v != v, do not work reliably and should not be used, lest your code stops working correctly when someone decides that floating point optimization is needed, and asks the compiler to do that. This situation can change, compilers can get more conforming, but for this issue that hasn't happened in the 6 years since the original answer.
For about 6 years my original answer was the selected solution for this question, which was OK. But recently a highly upvoted answer recommending the unreliable v != v test has been selected. Hence this additional more up-to-date answer (we now have the C++11 and C++14 standards, and C++17 on the horizon).
The main ways to check for NaN-ness, as of C++14, are:
std::isnan(value) )
is the intended standard library way since C++11. isnan apparently conflicts with the
Posix macro of the same name, but in practice that isn't a problem. The main problem is
that when floating point arithmetic optimization is requested, then with at least one main compiler, namely g++, std::isnan returns false for NaN argument.
(fpclassify(value) == FP_NAN) )
Suffers from the same problem as std::isnan, i.e., is not reliable.
(value != value) )
Recommended in many SO answers. Suffers from the same problem as std::isnan, i.e.,
is not reliable.
(value == Fp_info::quiet_NaN()) )
This is a test that with standard behavior should not detect NaNs, but that with the
optimized behavior maybe could detect NaNs (due to optimized code just comparing the
bitlevel representations directly), and perhaps combined with another way to
cover the standard un-optimized behavior, could reliably detect NaN. Unfortunately
it turned out to not work reliably.
(ilogb(value) == FP_ILOGBNAN) )
Suffers from the same problem as std::isnan, i.e., is not reliable.
isunordered(1.2345, value) )
Suffers from the same problem as std::isnan, i.e., is not reliable.
is_ieee754_nan( value ) )
This isn't a standard function. It's checking of the bits according to the IEEE 754
standard. It's completely reliable but the code is somewhat system-dependent.
In the following complete test code “success” is whether an expression reports Nan-ness of the value. For most expressions this measure of success, the goal of detecting NaNs and only NaNs, corresponds to their standard semantics. For the (value == Fp_info::quiet_NaN()) ) expression, however, the standard behavior is that it doesn't work as a NaN-detector.
#include <cmath> // std::isnan, std::fpclassify
#include <iostream>
#include <iomanip> // std::setw
#include <limits>
#include <limits.h> // CHAR_BIT
#include <sstream>
#include <stdint.h> // uint64_t
using namespace std;
#define TEST( x, expr, expected ) \
[&](){ \
const auto value = x; \
const bool result = expr; \
ostringstream stream; \
stream << boolalpha << #x " = " << x << ", (" #expr ") = " << result; \
cout \
<< setw( 60 ) << stream.str() << " " \
<< (result == expected? "Success" : "FAILED") \
<< endl; \
}()
#define TEST_ALL_VARIABLES( expression ) \
TEST( v, expression, true ); \
TEST( u, expression, false ); \
TEST( w, expression, false )
using Fp_info = numeric_limits<double>;
inline auto is_ieee754_nan( double const x )
-> bool
{
static constexpr bool is_claimed_ieee754 = Fp_info::is_iec559;
static constexpr int n_bits_per_byte = CHAR_BIT;
using Byte = unsigned char;
static_assert( is_claimed_ieee754, "!" );
static_assert( n_bits_per_byte == 8, "!" );
static_assert( sizeof( x ) == sizeof( uint64_t ), "!" );
#ifdef _MSC_VER
uint64_t const bits = reinterpret_cast<uint64_t const&>( x );
#else
Byte bytes[sizeof(x)];
memcpy( bytes, &x, sizeof( x ) );
uint64_t int_value;
memcpy( &int_value, bytes, sizeof( x ) );
uint64_t const& bits = int_value;
#endif
static constexpr uint64_t sign_mask = 0x8000000000000000;
static constexpr uint64_t exp_mask = 0x7FF0000000000000;
static constexpr uint64_t mantissa_mask = 0x000FFFFFFFFFFFFF;
(void) sign_mask;
return (bits & exp_mask) == exp_mask and (bits & mantissa_mask) != 0;
}
auto main()
-> int
{
double const v = Fp_info::quiet_NaN();
double const u = 3.14;
double const w = Fp_info::infinity();
cout << boolalpha << left;
cout << "Compiler claims IEEE 754 = " << Fp_info::is_iec559 << endl;
cout << endl;;
TEST_ALL_VARIABLES( std::isnan(value) ); cout << endl;
TEST_ALL_VARIABLES( (fpclassify(value) == FP_NAN) ); cout << endl;
TEST_ALL_VARIABLES( (value != value) ); cout << endl;
TEST_ALL_VARIABLES( (value == Fp_info::quiet_NaN()) ); cout << endl;
TEST_ALL_VARIABLES( (ilogb(value) == FP_ILOGBNAN) ); cout << endl;
TEST_ALL_VARIABLES( isunordered(1.2345, value) ); cout << endl;
TEST_ALL_VARIABLES( is_ieee754_nan( value ) );
}
Results with g++ (note again that the standard behavior of (value == Fp_info::quiet_NaN()) is that it doesn't work as a NaN-detector, it's just very much of practical interest here):
[C:\my\forums\so\282 (detect NaN)]
> g++ --version | find "++"
g++ (x86_64-win32-sjlj-rev1, Built by MinGW-W64 project) 6.3.0
[C:\my\forums\so\282 (detect NaN)]
> g++ foo.cpp && a
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = true Success
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 0x0100)) = true Success
u = 3.14, ((fpclassify(value) == 0x0100)) = false Success
w = inf, ((fpclassify(value) == 0x0100)) = false Success
v = nan, ((value != value)) = true Success
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED
u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success
w = inf, ((value == Fp_info::quiet_NaN())) = false Success
v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success
u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success
w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success
v = nan, (isunordered(1.2345, value)) = true Success
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> g++ foo.cpp -ffast-math && a
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = false FAILED
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 0x0100)) = false FAILED
u = 3.14, ((fpclassify(value) == 0x0100)) = false Success
w = inf, ((fpclassify(value) == 0x0100)) = false Success
v = nan, ((value != value)) = false FAILED
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = true Success
u = 3.14, ((value == Fp_info::quiet_NaN())) = true FAILED
w = inf, ((value == Fp_info::quiet_NaN())) = true FAILED
v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success
u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success
w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success
v = nan, (isunordered(1.2345, value)) = false FAILED
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> _
Results with Visual C++:
[C:\my\forums\so\282 (detect NaN)]
> cl /nologo- 2>&1 | find "++"
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23725 for x86
[C:\my\forums\so\282 (detect NaN)]
> cl foo.cpp /Feb && b
foo.cpp
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = true Success
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 2)) = true Success
u = 3.14, ((fpclassify(value) == 2)) = false Success
w = inf, ((fpclassify(value) == 2)) = false Success
v = nan, ((value != value)) = true Success
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED
u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success
w = inf, ((value == Fp_info::quiet_NaN())) = false Success
v = nan, ((ilogb(value) == 0x7fffffff)) = true Success
u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success
w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED
v = nan, (isunordered(1.2345, value)) = true Success
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> cl foo.cpp /Feb /fp:fast && b
foo.cpp
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = true Success
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 2)) = true Success
u = 3.14, ((fpclassify(value) == 2)) = false Success
w = inf, ((fpclassify(value) == 2)) = false Success
v = nan, ((value != value)) = true Success
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED
u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success
w = inf, ((value == Fp_info::quiet_NaN())) = false Success
v = nan, ((ilogb(value) == 0x7fffffff)) = true Success
u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success
w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED
v = nan, (isunordered(1.2345, value)) = true Success
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> _
Summing up the above results, only direct testing of the bit-level representation, using the is_ieee754_nan function defined in this test program, worked reliably in all cases with both g++ and Visual C++.
Addendum:
After posting the above I became aware of yet another possible to test for NaN, mentioned in another answer here, namely ((value < 0) == (value >= 0)). That turned out to work fine with Visual C++ but failed with g++'s -ffast-math option. Only direct bitpattern testing works reliably.
The following code uses the definition of NAN (all exponent bits set, at least one fractional bit set) and assumes that sizeof(int) = sizeof(float) = 4. You can look up NAN in Wikipedia for the details.
bool IsNan( float value )
{
return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000;
}
nan prevention
My answer to this question is don't use retroactive checks for nan. Use preventive checks for divisions of the form 0.0/0.0 instead.
#include <float.h>
float x=0.f ; // I'm gonna divide by x!
if( !x ) // Wait! Let me check if x is 0
x = FLT_MIN ; // oh, since x was 0, i'll just make it really small instead.
float y = 0.f / x ; // whew, `nan` didn't appear.
nan results from the operation 0.f/0.f, or 0.0/0.0. nan is a terrible nemesis to the stability of your code that must be detected and prevented very carefully1. The properties of nan that are different from normal numbers:
nan is toxic, (5*nan=nan)
nan is not equal to anything, not even itself (nan != nan)
nan not greater than anything (nan !> 0)
nan is not less than anything (nan !< 0)
The last 2 properties listed are counter-logical and will result in odd behavior of code that relies on comparisons with a nan number (the 3rd last property is odd too but you're probably not ever going to see x != x ? in your code (unless you are checking for nan (unreliably))).
In my own code, I noticed that nan values tend to produce difficult to find bugs. (Note how this is not the case for inf or -inf. (-inf < 0) returns TRUE, ( 0 < inf ) returns TRUE, and even (-inf < inf) returns TRUE. So, in my experience, the behavior of the code is often still as desired).
what to do under nan
What you want to happen under 0.0/0.0 must be handled as a special case, but what you do must depend on the numbers you expect to come out of the code.
In the example above, the result of (0.f/FLT_MIN) will be 0, basically. You may want 0.0/0.0 to generate HUGE instead. So,
float x=0.f, y=0.f, z;
if( !x && !y ) // 0.f/0.f case
z = FLT_MAX ; // biggest float possible
else
z = y/x ; // regular division.
So in the above, if x were 0.f, inf would result (which has pretty good/nondestructive behavior as mentioned above actually).
Remember, integer division by 0 causes a runtime exception. So you must always check for integer division by 0. Just because 0.0/0.0 quietly evaluates to nan doesn't mean you can be lazy and not check for 0.0/0.0 before it happens.
1 Checks for nan via x != x are sometimes unreliable (x != x being stripped out by some optimizing compilers that break IEEE compliance, specifically when the -ffast-math switch is enabled).
inline bool IsNan(float f)
{
const uint32 u = *(uint32*)&f;
return (u&0x7F800000) == 0x7F800000 && (u&0x7FFFFF); // Both NaN and qNan.
}
inline bool IsNan(double d)
{
const uint64 u = *(uint64*)&d;
return (u&0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && (u&0xFFFFFFFFFFFFFULL);
}
This works if sizeof(int) is 4 and sizeof(long long) is 8.
During run time it is only comparison, castings do not take any time. It just changes comparison flags configuration to check equality.
A possible solution that would not depend on the specific IEEE representation for NaN used would be the following:
template<class T>
bool isnan( T f ) {
T _nan = (T)0.0/(T)0.0;
return 0 == memcmp( (void*)&f, (void*)&_nan, sizeof(T) );
}
Considering that (x != x) is not always guaranteed for NaN (such as if using the -ffast-math option), I've been using:
#define IS_NAN(x) (((x) < 0) == ((x) >= 0))
Numbers can't be both < 0 and >= 0, so really this check only passes if the number is neither less than, nor greater than or equal to zero. Which is basically no number at all, or NaN.
You could also use this if you prefer:
#define IS_NAN(x) (!((x)<0) && !((x)>=0)
I'm not sure how this is affected by -ffast-math though, so your mileage may vary.
As for me the solution could be a macro to make it explicitly inline and thus fast enough.
It also works for any float type. It bases on the fact that the only case when a value is not equals itself is when the value is not a number.
#ifndef isnan
#define isnan(a) (a != a)
#endif
This works:
#include <iostream>
#include <math.h>
using namespace std;
int main ()
{
char ch='a';
double val = nan(&ch);
if(isnan(val))
cout << "isnan" << endl;
return 0;
}
output: isnan
It seems to me that the best truly cross-platform approach would be to use a union and to test the bit pattern of the double to check for NaNs.
I have not thoroughly tested this solution, and there may be a more efficient way of working with the bit patterns, but I think that it should work.
#include <stdint.h>
#include <stdio.h>
union NaN
{
uint64_t bits;
double num;
};
int main()
{
//Test if a double is NaN
double d = 0.0 / 0.0;
union NaN n;
n.num = d;
if((n.bits | 0x800FFFFFFFFFFFFF) == 0xFFFFFFFFFFFFFFFF)
{
printf("NaN: %f", d);
}
return 0;
}
On x86-64 you can have extremely fast methods for checking for NaN and infinity, which work regardless of -ffast-math compiler option. (f != f, std::isnan, std::isinf always yield false with -ffast-math).
Testing for NaN, infinity and finite numbers can easily be done by checking for maximum exponent. infinity is maximum exponent with zero mantissa, NaN is maximum exponent and non-zero mantissa. The exponent is stored in the next bits after the topmost sign bit, so that we can just left shift to get rid of the sign bit and make the exponent the topmost bits, no masking (operator&) is necessary:
static inline uint64_t load_ieee754_rep(double a) {
uint64_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movq instruction.
return r;
}
static inline uint32_t load_ieee754_rep(float a) {
uint32_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movd instruction.
return r;
}
constexpr uint64_t inf_double_shl1 = UINT64_C(0xffe0000000000000);
constexpr uint32_t inf_float_shl1 = UINT32_C(0xff000000);
// The shift left removes the sign bit. The exponent moves into the topmost bits,
// so that plain unsigned comparison is enough.
static inline bool isnan2(double a) { return load_ieee754_rep(a) << 1 > inf_double_shl1; }
static inline bool isinf2(double a) { return load_ieee754_rep(a) << 1 == inf_double_shl1; }
static inline bool isfinite2(double a) { return load_ieee754_rep(a) << 1 < inf_double_shl1; }
static inline bool isnan2(float a) { return load_ieee754_rep(a) << 1 > inf_float_shl1; }
static inline bool isinf2(float a) { return load_ieee754_rep(a) << 1 == inf_float_shl1; }
static inline bool isfinite2(float a) { return load_ieee754_rep(a) << 1 < inf_float_shl1; }
The std versions of isinf and isfinite load 2 double/float constants from .data segment and in the worst case scenario they can cause 2 data cache misses. The above versions do not load any data, inf_double_shl1 and inf_float_shl1 constants get encoded as immediate operands into the assembly instructions.
Faster isnan2 is just 2 assembly instructions:
bool isnan2(double a) {
bool r;
asm(".intel_syntax noprefix"
"\n\t ucomisd %1, %1"
"\n\t setp %b0"
"\n\t .att_syntax prefix"
: "=g" (r)
: "x" (a)
: "cc"
);
return r;
}
Uses the fact that ucomisd instruction sets parity flag if any argument is NaN. This is how std::isnan works when no -ffast-math options is specified.
The IEEE standard says
when the exponent is all 1s
and
the mantissa is not zero,
the number is a NaN.
Double is 1 sign bit, 11 exponent bits and 52 mantissa bits.
Do a bit check.
As comments above state a != a will not work in g++ and some other compilers, but this trick should. It may not be as efficient, but it's still a way:
bool IsNan(float a)
{
char s[4];
sprintf(s, "%.3f", a);
if (s[0]=='n') return true;
else return false;
}
Basically, in g++ (I am not sure about others though) printf prints 'nan' on %d or %.f formats if variable is not a valid integer/float. Therefore this code is checking for the first character of string to be 'n' (as in "nan")
This detects infinity and also NaN in Visual Studio by checking it is within double limits:
//#include <float.h>
double x, y = -1.1; x = sqrt(y);
if (x >= DBL_MIN && x <= DBL_MAX )
cout << "DETECTOR-2 of errors FAILS" << endl;
else
cout << "DETECTOR-2 of errors OK" << endl;
#include <iostream>
using namespace std;
int main() {
// your code goes here
int x=1;
int y;
y=x&&10;
cout<<y;
return 0;
}
The output is 1.
How is the value stored in y? What is the operation of &&? Please explain.
This operation
y=x&&10;
is evaluated as:
x && 10
1 (int) && 10 (int)
true && true // Note any non-zero integer will be evaluated to true
true
Therefore
y = true
But y is an int, so then there is an implicit conversion from bool back to int, which results in y being 1.
If you write "a && b" then both of the variables a and b must equate to true, for the result of the expression to return true, otherwise false will be the result.
For integers, all values which are not zero are considered true. Both of your variables are non-zero so your expression returns true.
When a boolean is stored into an integer, true is expressed as 1 whilst false is expressed as zero.
This is why your application outputs 1.
y=0 only if you put 0 instead of 10 or assign 0 to x.
if the values of left hand operand and right hand operand both are non-zero y=1 as both represents true.
if one of the operand is 0 then y=0 as 0 represents false.
I have written this C++ program, and I am not able to understand why it is printing 1 in the third cout statement.
#include<iostream>
using namespace std;
int main()
{
bool b = false;
cout << b << "\n"; // Print 0
b = ~b;
cout << b << "\n"; // Print 1
b = ~b;
cout << b << "\n"; // Print 1 **Why?**
return 0;
}
Output:
0
1
1
Why is it not printing the following?
0
1
0
This is due to C legacy operator mechanization (also recalling that ~ is bitwise complement). Integral operands to ~ are promoted to int before doing the operation, then converted back to bool. So effectively what you're getting is (using unsigned 32 bit representation) false -> 0 -> 0xFFFFFFFF -> true. Then true -> 1 -> 0xFFFFFFFE -> 1 -> true.
You're looking for the ! operator to invert a boolean value.
You probably want to do this:
b = !b;
which is logical negation. What you did is bitwise negation of a bool cast to an integer. The second time the statement b = ~b; is executed, the prior value of b is true. Cast to an integer this gives 1 whose bitwise complement is -2 and hence cast back to bool true. Therefore, true values of b will remain true while false values will be assigned true. This is due to the C legacy.
As pretty much everyone else has said, the bool is getting promoted to an integer before the complement operator is getting its work done. ~ is a bitwise operator and thus inverts each individual bit of the integer; if you apply ~ to 00000001, the result is 11111110. When you apply this to a 32-bit signed integer, ~1 gives you -2. If you're confused why, just take a look at a binary converter. For example: http://www.binaryconvert.com/result_signed_int.html?decimal=045050
To your revised question:
False to true works for the same reason as above. If you flip 00000000 (out to 32 bits), you get 11111111... which I believe is -1 in integer. When comparing boolean values, anything that is -not- 0 is considered to be true, while 0 alone is false.
You should use logical operators, not binary operators. Use ! instead of ~.
I've been struggling for a while with a part of my code and I finally found that the problem lies with a simple test that don't give me the result I expect.
if (2) //=> true
if (2 & true) //=> false
if (bool(2) & true) //=> true
What I don't understand is why the second line results in false.
My understanding was that every non-zero integer was considered as true in a test.
Because the bitwise and between 2 and true is false.
& (bitwise operator) is different than && (logical operator).
true cast to int is 1.
So 2 & true is 2 & 1 which is false - because 0000000000000010 & 0000000000000001 == 0. (bits may vary)
Whereas bool(2) == 1, and 1 & 1 is true.
if (2) //=> true
So far, so good.
if (2 & true) //=> false
The condition here evaluates to 2 & 1 == 0, because & is a bitwise operator and 2 and 1 are respectively 00000010 and 00000001 in binary.
if (bool(2) & true) //=> true
Interestingly enough, on my compiler I seem to recall erratic behavior in some cases like this; and, if sect. 4.12 of the C++11 standard addresses the matter, it does so in a manner I do not understand. I seem to recall seeing my compiler let bool(2) == 2, which one would not expect. Whether this represents a bug in my compiler or a fault in my recollection, I do not know.
I suspect however that you want the logical operator && rather than the bitwise operator &.
QUIZ
To check your understanding, try
if (3 & true) //=> true
Do you understand why? (Hint: the binary representation of 3 is 00000011.)
You need && instead of &.
&& is the boolean and operator, whereas & is the binary 'and' so 2 & true is the same as 0010 & 0001 = 0000 -> false whereas 2 && true = true.
& does an AND between all the bits (call bitwise AND) , what you need is the && operator (boolean AND).
2 in binary is '10' and true is 1 (01) in binary, the result 10 & 01 is therefore 0 .
bool(2) convert 2 to true , is 01 in binary, and 01 & 01 is 01.
Is there an isnan() function?
PS.: I'm in MinGW (if that makes a difference).
I had this solved by using isnan() from <math.h>, which doesn't exist in <cmath>, which I was #includeing at first.
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.
There is no isnan() function available in current C++ Standard Library. It was introduced in C99 and defined as a macro not a function. Elements of standard library defined by C99 are not part of current C++ standard ISO/IEC 14882:1998 neither its update ISO/IEC 14882:2003.
In 2005 Technical Report 1 was proposed. The TR1 brings compatibility with C99 to C++. In spite of the fact it has never been officially adopted to become C++ standard, many (GCC 4.0+ or Visual C++ 9.0+ C++ implementations do provide TR1 features, all of them or only some (Visual C++ 9.0 does not provide C99 math functions).
If TR1 is available, then cmath includes C99 elements like isnan(), isfinite(), etc. but they are defined as functions, not macros, usually in std::tr1:: namespace, though many implementations (i.e. GCC 4+ on Linux or in XCode on Mac OS X 10.5+) inject them directly to std::, so std::isnan is well defined.
Moreover, some implementations of C++ still make C99 isnan() macro available for C++ (included through cmath or math.h), what may cause more confusions and developers may assume it's a standard behaviour.
A note about Viusal C++, as mentioned above, it does not provide std::isnan neither std::tr1::isnan, but it provides an extension function defined as _isnan() which has been available since Visual C++ 6.0
On XCode, there is even more fun. As mentioned, GCC 4+ defines std::isnan. For older versions of compiler and library form XCode, it seems (here is relevant discussion), haven't had chance to check myself) two functions are defined, __inline_isnand() on Intel and __isnand() on Power PC.
First solution: if you are using C++11
Since this was asked there were a bit of new developments: it is important to know that std::isnan() is part of C++11
Synopsis
Defined in header <cmath>
bool isnan( float arg ); (since C++11)
bool isnan( double arg ); (since C++11)
bool isnan( long double arg ); (since C++11)
Determines if the given floating point number arg is not-a-number (NaN).
Parameters
arg: floating point value
Return value
true if arg is NaN, false otherwise
Reference
http://en.cppreference.com/w/cpp/numeric/math/isnan
Please note that this is incompatible with -fast-math if you use g++, see below for other suggestions.
Other solutions: if you using non C++11 compliant tools
For C99, in C, this is implemented as a macro isnan(c)that returns an int value. The type of x shall be float, double or long double.
Various vendors may or may not include or not a function isnan().
The supposedly portable way to check for NaN is to use the IEEE 754 property that NaN is not equal to itself: i.e. x == x will be false for x being NaN.
However the last option may not work with every compiler and some settings (particularly optimisation settings), so in last resort, you can always check the bit pattern ...
There is also a header-only library present in Boost that have neat tools to deal with floating point datatypes
#include <boost/math/special_functions/fpclassify.hpp>
You get the following functions:
template <class T> bool isfinite(T z);
template <class T> bool isinf(T t);
template <class T> bool isnan(T t);
template <class T> bool isnormal(T t);
If you have time then have a look at whole Math toolkit from Boost, it has many useful tools and is growing quickly.
Also when dealing with floating and non-floating points it might be a good idea to look at the Numeric Conversions.
There are three "official" ways: posix isnan macro, c++0x isnan function template, or visual c++ _isnan function.
Unfortunately it's rather impractical to detect which of those to use.
And unfortunately, there's no reliable way to detect whether you have IEEE 754 representation with NaNs. The standard library offers an official such way (numeric_limits<double>::is_iec559). But in practice compilers such as g++ screw that up.
In theory one could use simply x != x, but compilers such as g++ and visual c++ screw that up.
So in the end, test for the specific NaN bitpatterns, assuming (and hopefully enforcing, at some point!) a particular representation such as IEEE 754.
EDIT: as an example of "compilers such as g++ … screw that up", consider
#include <limits>
#include <assert.h>
void foo( double a, double b )
{
assert( a != b );
}
int main()
{
typedef std::numeric_limits<double> Info;
double const nan1 = Info::quiet_NaN();
double const nan2 = Info::quiet_NaN();
foo( nan1, nan2 );
}
Compiling with g++ (TDM-2 mingw32) 4.4.1:
C:\test> type "C:\Program Files\#commands\gnuc.bat"
#rem -finput-charset=windows-1252
#g++ -O -pedantic -std=c++98 -Wall -Wwrite-strings %* -Wno-long-long
C:\test> gnuc x.cpp
C:\test> a && echo works... || echo !failed
works...
C:\test> gnuc x.cpp --fast-math
C:\test> a && echo works... || echo !failed
Assertion failed: a != b, file x.cpp, line 6
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
!failed
C:\test> _
There is an std::isnan if you compiler supports c99 extensions, but I'm not sure if mingw does.
Here is a small function which should work if your compiler doesn't have the standard function:
bool custom_isnan(double var)
{
volatile double d = var;
return d != d;
}
You can use numeric_limits<float>::quiet_NaN( ) defined in the limits standard library to test with. There's a separate constant defined for double.
#include <iostream>
#include <math.h>
#include <limits>
using namespace std;
int main( )
{
cout << "The quiet NaN for type float is: "
<< numeric_limits<float>::quiet_NaN( )
<< endl;
float f_nan = numeric_limits<float>::quiet_NaN();
if( isnan(f_nan) )
{
cout << "Float was Not a Number: " << f_nan << endl;
}
return 0;
}
I don't know if this works on all platforms, as I only tested with g++ on Linux.
You can use the isnan() function, but you need to include the C math library.
#include <cmath>
As this function is part of C99, it is not available everywhere. If your vendor does not supply the function, you can also define your own variant for compatibility.
inline bool isnan(double x) {
return x != x;
}
As of C++14 there are a number of ways to test if a floating point number value is a NaN.
Of these ways, only checking of the bits of the number's representation,
works reliably, as noted in my original answer. In particular, std::isnan and the often proposed check v != v, do not work reliably and should not be used, lest your code stops working correctly when someone decides that floating point optimization is needed, and asks the compiler to do that. This situation can change, compilers can get more conforming, but for this issue that hasn't happened in the 6 years since the original answer.
For about 6 years my original answer was the selected solution for this question, which was OK. But recently a highly upvoted answer recommending the unreliable v != v test has been selected. Hence this additional more up-to-date answer (we now have the C++11 and C++14 standards, and C++17 on the horizon).
The main ways to check for NaN-ness, as of C++14, are:
std::isnan(value) )
is the intended standard library way since C++11. isnan apparently conflicts with the
Posix macro of the same name, but in practice that isn't a problem. The main problem is
that when floating point arithmetic optimization is requested, then with at least one main compiler, namely g++, std::isnan returns false for NaN argument.
(fpclassify(value) == FP_NAN) )
Suffers from the same problem as std::isnan, i.e., is not reliable.
(value != value) )
Recommended in many SO answers. Suffers from the same problem as std::isnan, i.e.,
is not reliable.
(value == Fp_info::quiet_NaN()) )
This is a test that with standard behavior should not detect NaNs, but that with the
optimized behavior maybe could detect NaNs (due to optimized code just comparing the
bitlevel representations directly), and perhaps combined with another way to
cover the standard un-optimized behavior, could reliably detect NaN. Unfortunately
it turned out to not work reliably.
(ilogb(value) == FP_ILOGBNAN) )
Suffers from the same problem as std::isnan, i.e., is not reliable.
isunordered(1.2345, value) )
Suffers from the same problem as std::isnan, i.e., is not reliable.
is_ieee754_nan( value ) )
This isn't a standard function. It's checking of the bits according to the IEEE 754
standard. It's completely reliable but the code is somewhat system-dependent.
In the following complete test code “success” is whether an expression reports Nan-ness of the value. For most expressions this measure of success, the goal of detecting NaNs and only NaNs, corresponds to their standard semantics. For the (value == Fp_info::quiet_NaN()) ) expression, however, the standard behavior is that it doesn't work as a NaN-detector.
#include <cmath> // std::isnan, std::fpclassify
#include <iostream>
#include <iomanip> // std::setw
#include <limits>
#include <limits.h> // CHAR_BIT
#include <sstream>
#include <stdint.h> // uint64_t
using namespace std;
#define TEST( x, expr, expected ) \
[&](){ \
const auto value = x; \
const bool result = expr; \
ostringstream stream; \
stream << boolalpha << #x " = " << x << ", (" #expr ") = " << result; \
cout \
<< setw( 60 ) << stream.str() << " " \
<< (result == expected? "Success" : "FAILED") \
<< endl; \
}()
#define TEST_ALL_VARIABLES( expression ) \
TEST( v, expression, true ); \
TEST( u, expression, false ); \
TEST( w, expression, false )
using Fp_info = numeric_limits<double>;
inline auto is_ieee754_nan( double const x )
-> bool
{
static constexpr bool is_claimed_ieee754 = Fp_info::is_iec559;
static constexpr int n_bits_per_byte = CHAR_BIT;
using Byte = unsigned char;
static_assert( is_claimed_ieee754, "!" );
static_assert( n_bits_per_byte == 8, "!" );
static_assert( sizeof( x ) == sizeof( uint64_t ), "!" );
#ifdef _MSC_VER
uint64_t const bits = reinterpret_cast<uint64_t const&>( x );
#else
Byte bytes[sizeof(x)];
memcpy( bytes, &x, sizeof( x ) );
uint64_t int_value;
memcpy( &int_value, bytes, sizeof( x ) );
uint64_t const& bits = int_value;
#endif
static constexpr uint64_t sign_mask = 0x8000000000000000;
static constexpr uint64_t exp_mask = 0x7FF0000000000000;
static constexpr uint64_t mantissa_mask = 0x000FFFFFFFFFFFFF;
(void) sign_mask;
return (bits & exp_mask) == exp_mask and (bits & mantissa_mask) != 0;
}
auto main()
-> int
{
double const v = Fp_info::quiet_NaN();
double const u = 3.14;
double const w = Fp_info::infinity();
cout << boolalpha << left;
cout << "Compiler claims IEEE 754 = " << Fp_info::is_iec559 << endl;
cout << endl;;
TEST_ALL_VARIABLES( std::isnan(value) ); cout << endl;
TEST_ALL_VARIABLES( (fpclassify(value) == FP_NAN) ); cout << endl;
TEST_ALL_VARIABLES( (value != value) ); cout << endl;
TEST_ALL_VARIABLES( (value == Fp_info::quiet_NaN()) ); cout << endl;
TEST_ALL_VARIABLES( (ilogb(value) == FP_ILOGBNAN) ); cout << endl;
TEST_ALL_VARIABLES( isunordered(1.2345, value) ); cout << endl;
TEST_ALL_VARIABLES( is_ieee754_nan( value ) );
}
Results with g++ (note again that the standard behavior of (value == Fp_info::quiet_NaN()) is that it doesn't work as a NaN-detector, it's just very much of practical interest here):
[C:\my\forums\so\282 (detect NaN)]
> g++ --version | find "++"
g++ (x86_64-win32-sjlj-rev1, Built by MinGW-W64 project) 6.3.0
[C:\my\forums\so\282 (detect NaN)]
> g++ foo.cpp && a
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = true Success
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 0x0100)) = true Success
u = 3.14, ((fpclassify(value) == 0x0100)) = false Success
w = inf, ((fpclassify(value) == 0x0100)) = false Success
v = nan, ((value != value)) = true Success
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED
u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success
w = inf, ((value == Fp_info::quiet_NaN())) = false Success
v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success
u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success
w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success
v = nan, (isunordered(1.2345, value)) = true Success
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> g++ foo.cpp -ffast-math && a
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = false FAILED
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 0x0100)) = false FAILED
u = 3.14, ((fpclassify(value) == 0x0100)) = false Success
w = inf, ((fpclassify(value) == 0x0100)) = false Success
v = nan, ((value != value)) = false FAILED
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = true Success
u = 3.14, ((value == Fp_info::quiet_NaN())) = true FAILED
w = inf, ((value == Fp_info::quiet_NaN())) = true FAILED
v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success
u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success
w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success
v = nan, (isunordered(1.2345, value)) = false FAILED
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> _
Results with Visual C++:
[C:\my\forums\so\282 (detect NaN)]
> cl /nologo- 2>&1 | find "++"
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23725 for x86
[C:\my\forums\so\282 (detect NaN)]
> cl foo.cpp /Feb && b
foo.cpp
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = true Success
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 2)) = true Success
u = 3.14, ((fpclassify(value) == 2)) = false Success
w = inf, ((fpclassify(value) == 2)) = false Success
v = nan, ((value != value)) = true Success
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED
u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success
w = inf, ((value == Fp_info::quiet_NaN())) = false Success
v = nan, ((ilogb(value) == 0x7fffffff)) = true Success
u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success
w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED
v = nan, (isunordered(1.2345, value)) = true Success
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> cl foo.cpp /Feb /fp:fast && b
foo.cpp
Compiler claims IEEE 754 = true
v = nan, (std::isnan(value)) = true Success
u = 3.14, (std::isnan(value)) = false Success
w = inf, (std::isnan(value)) = false Success
v = nan, ((fpclassify(value) == 2)) = true Success
u = 3.14, ((fpclassify(value) == 2)) = false Success
w = inf, ((fpclassify(value) == 2)) = false Success
v = nan, ((value != value)) = true Success
u = 3.14, ((value != value)) = false Success
w = inf, ((value != value)) = false Success
v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED
u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success
w = inf, ((value == Fp_info::quiet_NaN())) = false Success
v = nan, ((ilogb(value) == 0x7fffffff)) = true Success
u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success
w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED
v = nan, (isunordered(1.2345, value)) = true Success
u = 3.14, (isunordered(1.2345, value)) = false Success
w = inf, (isunordered(1.2345, value)) = false Success
v = nan, (is_ieee754_nan( value )) = true Success
u = 3.14, (is_ieee754_nan( value )) = false Success
w = inf, (is_ieee754_nan( value )) = false Success
[C:\my\forums\so\282 (detect NaN)]
> _
Summing up the above results, only direct testing of the bit-level representation, using the is_ieee754_nan function defined in this test program, worked reliably in all cases with both g++ and Visual C++.
Addendum:
After posting the above I became aware of yet another possible to test for NaN, mentioned in another answer here, namely ((value < 0) == (value >= 0)). That turned out to work fine with Visual C++ but failed with g++'s -ffast-math option. Only direct bitpattern testing works reliably.
The following code uses the definition of NAN (all exponent bits set, at least one fractional bit set) and assumes that sizeof(int) = sizeof(float) = 4. You can look up NAN in Wikipedia for the details.
bool IsNan( float value )
{
return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000;
}
nan prevention
My answer to this question is don't use retroactive checks for nan. Use preventive checks for divisions of the form 0.0/0.0 instead.
#include <float.h>
float x=0.f ; // I'm gonna divide by x!
if( !x ) // Wait! Let me check if x is 0
x = FLT_MIN ; // oh, since x was 0, i'll just make it really small instead.
float y = 0.f / x ; // whew, `nan` didn't appear.
nan results from the operation 0.f/0.f, or 0.0/0.0. nan is a terrible nemesis to the stability of your code that must be detected and prevented very carefully1. The properties of nan that are different from normal numbers:
nan is toxic, (5*nan=nan)
nan is not equal to anything, not even itself (nan != nan)
nan not greater than anything (nan !> 0)
nan is not less than anything (nan !< 0)
The last 2 properties listed are counter-logical and will result in odd behavior of code that relies on comparisons with a nan number (the 3rd last property is odd too but you're probably not ever going to see x != x ? in your code (unless you are checking for nan (unreliably))).
In my own code, I noticed that nan values tend to produce difficult to find bugs. (Note how this is not the case for inf or -inf. (-inf < 0) returns TRUE, ( 0 < inf ) returns TRUE, and even (-inf < inf) returns TRUE. So, in my experience, the behavior of the code is often still as desired).
what to do under nan
What you want to happen under 0.0/0.0 must be handled as a special case, but what you do must depend on the numbers you expect to come out of the code.
In the example above, the result of (0.f/FLT_MIN) will be 0, basically. You may want 0.0/0.0 to generate HUGE instead. So,
float x=0.f, y=0.f, z;
if( !x && !y ) // 0.f/0.f case
z = FLT_MAX ; // biggest float possible
else
z = y/x ; // regular division.
So in the above, if x were 0.f, inf would result (which has pretty good/nondestructive behavior as mentioned above actually).
Remember, integer division by 0 causes a runtime exception. So you must always check for integer division by 0. Just because 0.0/0.0 quietly evaluates to nan doesn't mean you can be lazy and not check for 0.0/0.0 before it happens.
1 Checks for nan via x != x are sometimes unreliable (x != x being stripped out by some optimizing compilers that break IEEE compliance, specifically when the -ffast-math switch is enabled).
inline bool IsNan(float f)
{
const uint32 u = *(uint32*)&f;
return (u&0x7F800000) == 0x7F800000 && (u&0x7FFFFF); // Both NaN and qNan.
}
inline bool IsNan(double d)
{
const uint64 u = *(uint64*)&d;
return (u&0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && (u&0xFFFFFFFFFFFFFULL);
}
This works if sizeof(int) is 4 and sizeof(long long) is 8.
During run time it is only comparison, castings do not take any time. It just changes comparison flags configuration to check equality.
A possible solution that would not depend on the specific IEEE representation for NaN used would be the following:
template<class T>
bool isnan( T f ) {
T _nan = (T)0.0/(T)0.0;
return 0 == memcmp( (void*)&f, (void*)&_nan, sizeof(T) );
}
Considering that (x != x) is not always guaranteed for NaN (such as if using the -ffast-math option), I've been using:
#define IS_NAN(x) (((x) < 0) == ((x) >= 0))
Numbers can't be both < 0 and >= 0, so really this check only passes if the number is neither less than, nor greater than or equal to zero. Which is basically no number at all, or NaN.
You could also use this if you prefer:
#define IS_NAN(x) (!((x)<0) && !((x)>=0)
I'm not sure how this is affected by -ffast-math though, so your mileage may vary.
As for me the solution could be a macro to make it explicitly inline and thus fast enough.
It also works for any float type. It bases on the fact that the only case when a value is not equals itself is when the value is not a number.
#ifndef isnan
#define isnan(a) (a != a)
#endif
This works:
#include <iostream>
#include <math.h>
using namespace std;
int main ()
{
char ch='a';
double val = nan(&ch);
if(isnan(val))
cout << "isnan" << endl;
return 0;
}
output: isnan
It seems to me that the best truly cross-platform approach would be to use a union and to test the bit pattern of the double to check for NaNs.
I have not thoroughly tested this solution, and there may be a more efficient way of working with the bit patterns, but I think that it should work.
#include <stdint.h>
#include <stdio.h>
union NaN
{
uint64_t bits;
double num;
};
int main()
{
//Test if a double is NaN
double d = 0.0 / 0.0;
union NaN n;
n.num = d;
if((n.bits | 0x800FFFFFFFFFFFFF) == 0xFFFFFFFFFFFFFFFF)
{
printf("NaN: %f", d);
}
return 0;
}
On x86-64 you can have extremely fast methods for checking for NaN and infinity, which work regardless of -ffast-math compiler option. (f != f, std::isnan, std::isinf always yield false with -ffast-math).
Testing for NaN, infinity and finite numbers can easily be done by checking for maximum exponent. infinity is maximum exponent with zero mantissa, NaN is maximum exponent and non-zero mantissa. The exponent is stored in the next bits after the topmost sign bit, so that we can just left shift to get rid of the sign bit and make the exponent the topmost bits, no masking (operator&) is necessary:
static inline uint64_t load_ieee754_rep(double a) {
uint64_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movq instruction.
return r;
}
static inline uint32_t load_ieee754_rep(float a) {
uint32_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movd instruction.
return r;
}
constexpr uint64_t inf_double_shl1 = UINT64_C(0xffe0000000000000);
constexpr uint32_t inf_float_shl1 = UINT32_C(0xff000000);
// The shift left removes the sign bit. The exponent moves into the topmost bits,
// so that plain unsigned comparison is enough.
static inline bool isnan2(double a) { return load_ieee754_rep(a) << 1 > inf_double_shl1; }
static inline bool isinf2(double a) { return load_ieee754_rep(a) << 1 == inf_double_shl1; }
static inline bool isfinite2(double a) { return load_ieee754_rep(a) << 1 < inf_double_shl1; }
static inline bool isnan2(float a) { return load_ieee754_rep(a) << 1 > inf_float_shl1; }
static inline bool isinf2(float a) { return load_ieee754_rep(a) << 1 == inf_float_shl1; }
static inline bool isfinite2(float a) { return load_ieee754_rep(a) << 1 < inf_float_shl1; }
The std versions of isinf and isfinite load 2 double/float constants from .data segment and in the worst case scenario they can cause 2 data cache misses. The above versions do not load any data, inf_double_shl1 and inf_float_shl1 constants get encoded as immediate operands into the assembly instructions.
Faster isnan2 is just 2 assembly instructions:
bool isnan2(double a) {
bool r;
asm(".intel_syntax noprefix"
"\n\t ucomisd %1, %1"
"\n\t setp %b0"
"\n\t .att_syntax prefix"
: "=g" (r)
: "x" (a)
: "cc"
);
return r;
}
Uses the fact that ucomisd instruction sets parity flag if any argument is NaN. This is how std::isnan works when no -ffast-math options is specified.
The IEEE standard says
when the exponent is all 1s
and
the mantissa is not zero,
the number is a NaN.
Double is 1 sign bit, 11 exponent bits and 52 mantissa bits.
Do a bit check.
As comments above state a != a will not work in g++ and some other compilers, but this trick should. It may not be as efficient, but it's still a way:
bool IsNan(float a)
{
char s[4];
sprintf(s, "%.3f", a);
if (s[0]=='n') return true;
else return false;
}
Basically, in g++ (I am not sure about others though) printf prints 'nan' on %d or %.f formats if variable is not a valid integer/float. Therefore this code is checking for the first character of string to be 'n' (as in "nan")
This detects infinity and also NaN in Visual Studio by checking it is within double limits:
//#include <float.h>
double x, y = -1.1; x = sqrt(y);
if (x >= DBL_MIN && x <= DBL_MAX )
cout << "DETECTOR-2 of errors FAILS" << endl;
else
cout << "DETECTOR-2 of errors OK" << endl;