views:

17331

answers:

7

is there an isnan() function?

p.s. I'm in mingw (if that makes a difference)

UPDATE

Thanks for the responses

I had this solved by using isnan() form <math.h>, which doesn't exist in <cmath>, which I was #includeing at first.

+17  A: 

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;
}
CTT
why not just var != var?
Brian R. Bondy
When doing that their is a chance the compiler will optimize the comparison out, always returning true.
CTT
@CTT: No there isn't. A compiler that does that is broken. You might as well say that there's a chance that the standard library `isnan` returns the wrong result. Technically true, the compiler *could* be buggy, but in practice, Not Gonna Happen. Same as `var != var`. It works because that's how IEEE floating point values are defined.
jalf
+24  A: 

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.

jalf
Isn't it possible that the compiler will optimize this out though? (I don't know because I haven't used C++ for a long time)
DrJokepu
The compiler had better not remove this if running in an IEEE mode. Check the documentation for your compiler, of course...
dmckee
The compiler will not optimize this out. The only caveat is that this property applies to IEEE floating point values, but may not apply to other formats. Common platfors use IEEE so this is guaranteed to work on those, but on platforms using different fp formats, this trick doesn't work.
jalf
+7  A: 

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.

#ifndef isnan
inline bool isnan(double x) {
    return x != x;
}
#endif
Raim
I was using <cmath> and there's no isnan in it! incidentally I found out that there *is* an `isnan` in <math.h>
hasen j
As I said, this is part of C99. As C99 is not part of any current C++ standard, I provided the alternative. But as it is likely that isnan() will be included in an upcoming C++ standard, I put a #ifndef directive around it.
Raim
+10  A: 

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.

Bill the Lizard
Watch out, though--there appears to be a bug in numeric_limits in GCC version 3.2.3, since it returns 0.0 for quiet_NaN. Later versions of GCC are okay in my experience.
Nathan Kitchen
@Nathan: Good to know. I'm using version 4.3.2, so I'm well out of the woods.
Bill the Lizard
This will not work, since NaN's never compare equal to another floating point value, even themselves. Specifically "numeric_limits<float>::quiet_nan() == numeric_limits<float>::quiet_nan()" should always return false.
ReWrite
@ReWrite: I don't see how this "will not work" since what I suggested above is a test.
Bill the Lizard
+6  A: 

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.

Anonymous
Don't use backslashes for include paths. Forward slashes work everywhere (even Windows), backslashes don't.
Bklyn
Thanx, copy-pasta error.
Anonymous
A: 

I believe that the "C++ way" to do this is to either use Boost or do something like:

#if I_HAVE_TR1
#include <cmath> // defines std::tr1::isnan<T>
#else
#include <limits>
namespace std { namespace tr1 {
template <class T>
inline bool isnan(T val) {
    return ((std::numeric_limits<T>::has_quiet_NaN &&
             (std::numeric_limits<T>::quiet_NaN() == val)) ||
            (std::numeric_limits<T>::has_signaling_NaN &&
             (std::numeric_limits<T>::signaling_NaN() == val));
}
}} // end namespace std::tr1
#endif

or some less readable variant of that. IIRC, TR1 added in all of the math goodness from C99. Unfortunately I can't recall how to properly detect if the compilation environment supports TR1 :(

D.Shawley
what's the need for all this mess when it's so simple?? check the upvoted answers
hasen j
Not to mention that NaN doesn't equal anything, so this will not work.
bk1e
+6  A: 

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.

mloskot