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

后端 未结 21 1856
北恋
北恋 2020-11-22 05:10

Is there an isnan() function?

PS.: I\'m in MinGW (if that makes a difference).

I had this solved by using isnan() from , which doe

相关标签:
21条回答
  • 2020-11-22 05:23

    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.

    0 讨论(0)
  • 2020-11-22 05:23

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 05:27

    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> _
    
    0 讨论(0)
  • 2020-11-22 05:27

    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.

    0 讨论(0)
  • 2020-11-22 05:31

    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) );
    }
    
    0 讨论(0)
  • 2020-11-22 05:32

    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")

    0 讨论(0)
提交回复
热议问题