检查C ++中的double(或float)是否为NaN

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

有没有在isnan()函数?

PS:如果我让一个差分)。

这是我从isnan()使用,它不适合在存在,这在我#includeing第一。


根据IEEE标准,NaN值具有奇怪的特性,涉及它们的比较总是错误的。也就是说,对于浮点数f,只有当f为NaN时,f != f才是真的。

注意,正如下面的一些注释所指出的,并不是所有编译器在优化代码时都会尊重这一点。

对于声称使用IEEEfloatingpoint的任何编译器来说,这个技巧都是有效的。但我不能保证它会在实践中起作用。如果有疑问,请与编译器联系。


当前C++标准库中没有可用的EDCOX1 1函数。它是在c99中引入的,定义为宏而不是函数。C99定义的标准库的元素不是当前的C++标准ISO/IEC 1488∶1998的一部分,而不是其更新ISO/IEC 1488∶2003。

2005年提出了技术报告1。Tr1带来了与C99到C++的兼容性。尽管它从未被正式采纳成为C++标准,许多(GCC 4 +或Visual C++ 9+C++实现确实提供了Tr1特征,它们全部或仅一些(Visual C++ 9不提供C99数学函数)。

如果tr1可用,那么cmath包括c99元素,如isnan()isfinite()等,但它们被定义为函数,而不是宏,通常在std::tr1::命名空间中,尽管许多实现(即Linux上的gcc 4+或Mac OS X 10.5+上的xcode)直接将它们注入std::,所以std::isnan定义得很好。

此外,C++的一些实现仍然使C99 EDCOX1和1的宏可用于C++(包括通过EDCOX1、6或EDCOX1×14),这可能会造成更多混乱,开发人员可能会认为这是一种标准行为。

关于viiC++的注释,如上所述,它不提供EDCOX1〔11〕既不EDCOX1也不16,但它提供了一个扩展函数,定义为EDCOX1,17,这是自从Visual C++ 6以来可用的。

在Xcode上,还有更多的乐趣。如前所述,GCC4+定义了std::isnan。对于旧版本的编译器和库形式xcode,似乎(这里有相关的讨论),还没有机会检查自己)定义了两个函数,Intel上的__inline_isnand()和Power PC上的__isnand()


第一个解决方案:如果你使用C++ 11

因为这被问到有一些新的发展:重要的是知道EDCOX1的6个部分是C++ 11的一部分。

简介

在标题中定义

1
2
3
bool isnan( float arg ); (since C++11)
bool isnan( double arg ); (since C++11)
bool isnan( long double arg ); (since C++11)

确定给定的浮点数arg是否不是数字(NaN)。

参数

arg:浮点值

返回值

如果arg为NaN,则false,否则。

参考文献

http://en.cppreference.com/w/cpp/numeric/math/isnan

请注意,这与-fast math不兼容,如果您使用g++,请参阅下面的其他建议。

其他解决方案:如果使用非C++ 11兼容工具

对于c99,在c中,这是作为返回int值的宏isnan(c)实现的。x的类型应为浮动、双或长双。

不同的供应商可能包括也可能不包括一个函数isnan()

假设检查NaN的可移植方法是使用NaN不等于自身的ieee 754属性:即,x == x对于xNaN是错误的。

但是,最后一个选项可能无法与每个编译器和某些设置(特别是优化设置)一起使用,因此,在最后一个方法中,您可以始终检查位模式…


Boost中还存在一个只包含头的库,它具有处理浮点数据类型的简洁工具。

1
#include <boost/math/special_functions/fpclassify.hpp>

您可以获得以下功能:

1
2
3
4
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);

如果你有时间看一下Boost的整个数学工具包,它有许多有用的工具,并且正在快速增长。

同样,在处理浮点数和非浮点数时,最好查看数值转换。


有三种"官方"方式:POSIX EDCOX1,0宏,C++0X EDCOX1,0函数模板,或Visual C++ EDCOX1×2函数。

不幸的是,检测使用哪种方法是相当不切实际的。

不幸的是,没有可靠的方法来检测您是否有NAN的IEEE754表示。标准图书馆提供了一种官方的方式(numeric_limits::is_iec559)。但是在实践中,像g++这样的编译器会搞砸它。

理论上,可以简单地使用EDCOX1,4,但是编译器如G++和VisualC++将其放大。

因此,在最后,测试特定的NAN位模式,假设(并且希望在某个时刻强制执行!)一种特殊的表示法,如IEEE754。

编辑:作为"编译器如g++&hellip;搞砸它"的一个例子,考虑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <limits>
#include

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 );
}

用G++编译(TDM-2 mingW32)4.4.1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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> _


有一个STD::ISNN,如果编译器支持C99扩展,但我不知道是否MIW。

下面是一个小函数,如果您的编译器没有标准函数,它应该可以工作:

1
2
3
4
5
bool custom_isnan(double var)
{
    volatile double d = var;
    return d != d;
}


可以使用limits标准库中定义的numeric_limits::quiet_NaN( )进行测试。有一个单独的常量为double定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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;
}

我不知道这是否适用于所有平台,因为我只在Linux上用g++测试过。


您可以使用isnan()函数,但您需要包括C数学库。

1
#include <cmath>

由于此功能是C99的一部分,因此并非所有地方都可用。如果您的供应商不提供该函数,您还可以为兼容性定义自己的变体。

1
2
3
inline bool isnan(double x) {
    return x != x;
}


南防

我对这个问题的回答是不要对nan使用追溯检查。使用表格0.0/0.0的分部预防性检查代替。

1
2
3
4
5
#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.

nan0.f/0.f0.0/0.0手术的结果。nan是对代码稳定性的一个可怕的敌人,必须非常小心地检测和预防它1。nan的性质不同于正常数:

  • nan有毒,(5*nan=nan)
  • nan不等于任何东西,甚至不等于本身(nan!=nan)
  • nan不大于任何(EDOCX1〔0)!> 0)
  • nan不小于任何东西(EDOCX1〔0)!< 0)

所列的最后2个属性是反逻辑的,将导致代码行为异常,依赖于与nan号的比较(第3个最后一个属性也是奇数,但您可能永远不会在代码中看到x != x ?(除非您正在检查NaN(不可靠))。

在我自己的代码中,我注意到nan值往往产生难以发现的错误。(注意,对于inf-inf,情况并非如此。(-inf小于0)返回TRUE,(0<inf返回真,偶数(-inf<inf返回真。因此,在我的经验中,代码的行为通常仍然是需要的)。

在南部做什么

0.0/0.0下,您希望发生的事情必须作为一种特殊情况来处理,但是您要做的事情必须取决于您期望从代码中得到的数字。

在上面的例子中,(0.f/FLT_MIN的结果基本上是0。您可能希望0.0/0.0生成HUGE。所以,

1
2
3
4
5
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.

因此,在上述情况下,如果x为0.f,则会产生inf(实际上具有上述良好/无损的性能)。

记住,整数除以0会导致运行时异常。所以必须始终检查整数除以0。仅仅因为0.0/0.0悄悄地对nan进行评估,并不意味着你可以懒惰,在它发生之前不检查0.0/0.0

1通过x != x检查nan有时是不可靠的(x != x被一些优化编译器去掉,这些编译器破坏了IEEE遵从性,特别是当-ffast-math开关被启用时)。


以下代码使用NaN(所有指数位集,至少一个小数位集)的定义,并假定sizeof(int)=sizeof(float)=4。你可以在维基百科上查找Nan的详细信息。

bool IsNan( float value )
{
return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000;
}


对于C++ 14,有很多方法来测试浮点数EDOCX1·0是一个Na。

在这些方法中,只检查数字表示的位,如我最初的答案所述,工作可靠。特别是,std::isnan和经常建议的检查v != v,不能可靠地工作,不应该使用,以免当有人决定需要浮点优化时,代码停止正常工作,并要求编译器执行该操作。这种情况可以改变,编译器可以变得更加符合标准,但对于这个问题,自最初的答案以来6年内还没有发生过。

在大约6年的时间里,我最初的答案是这个问题的解决方案,这是可以的。但最近,一个高度乐观的建议不可靠的v != v测试的答案被选中。因此,这个额外的更新的答案(我们现在有C++ 11和C++ 14标准,以及C++ 17在地平线上)。

检查C++的14个主要方法是:

  • std::isnan(value) )是C++ 11以来的标准库方式。isnan显然与同名的posix宏,但实际上这不是问题。主要问题是当请求浮点算术优化时,那么至少有一个主编译器,即g++,std::isnan为nan参数返回false

  • 8与std::isnan的问题相同,即不可靠。

  • (value != value) )在许多这样的答案中推荐。与std::isnan的问题相同,即:不可靠。

  • (value == Fp_info::quiet_NaN()) )这是一个具有标准行为的测试,不应检测到nan,而是使用优化的行为可能会检测到nan(由于优化的代码只是比较直接进行位级表示),并可能与另一种覆盖标准未优化行为,能可靠检测到NaN。不幸地结果证明它不能可靠地工作。

  • (ilogb(value) == FP_ILOGBNAN) )std::isnan的问题相同,即不可靠。

  • isunordered(1.2345, value) )std::isnan的问题相同,即不可靠。

  • is_ieee754_nan( value ) )这不是标准功能。它是根据IEEE754检查位的。标准。它是完全可靠的,但代码在某种程度上依赖于系统。

在以下完整的测试代码中,"Success"是一个表达式是否报告了值的Nanness。对于大多数表达式来说,这种成功度量的目标是检测nan,而仅检测nan,这与它们的标准语义相对应。然而,对于(value == Fp_info::quiet_NaN()) )表达式,标准行为是它不能作为NaN检测器工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#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 ) );
}

使用g++的结果(再次注意,(value == Fp_info::quiet_NaN())的标准行为是它不作为NaN检测器工作,这只是非常有实际意义的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
[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)]
> _

Visual C++的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
[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)]
> _

综上所述,仅使用该测试程序中定义的EDCOX1 OR 20函数直接测试位级表示,在G+和Visual C++两种情况下都能可靠地工作。

附录:在发布上述内容之后,我意识到还有一种可能测试NaN,在这里的另一个答案中提到,即((value < 0) == (value >= 0))。结果是用Visual C++工作得很好,但是用G+++的EDCOX1×22选项失败了。只有直接的位模式测试才能可靠地工作。


1
2
3
4
5
6
7
8
9
10
11
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);
}

如果sizeof(int)为4,sizeof(long long)为8,则此方法有效。

在运行期间,这只是比较,铸件不需要任何时间。它只是更改比较标志配置以检查相等性。


对于我来说,解决方案可以是一个宏,使其显式内联,从而足够快。它也适用于任何浮动类型。它基于这样一个事实,即当一个值不等于它本身时,唯一的情况是该值不是一个数字。

1
2
3
#ifndef isnan
  #define isnan(a) (a != a)
#endif


考虑到这一点(X!=x)并不总是保证NaN(例如,如果使用-ffast数学选项),我一直使用:

1
#define IS_NAN(x) (((x) < 0) == ((x) >= 0))

数字不能同时小于0和大于等于0,因此实际上,只有当数字既不小于也不大于或等于零时,此检查才会通过。基本上没有数字,也就是NaN。

如果您愿意,也可以使用这个:

1
#define IS_NAN(x) (!((x)<0) && !((x)>=0)

我不知道这是如何受快速数学的影响,所以你的里程可能会有所不同。


不依赖于所用NAN的特定IEEE表示的可能解决方案如下:

1
2
3
4
5
template<class T>
bool isnan( T f ) {
    T _nan =  (T)0.0/(T)0.0;
    return 0 == memcmp( (void*)&f, (void*)&_nan, sizeof(T) );
}

这工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
#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;
}

输出:ISNEN


在我看来,最好的真正跨平台方法应该是使用联合和测试double的位模式来检查nan。

我还没有彻底测试过这个解决方案,也许有一种更有效的方式来处理位模式,但是我认为它应该可以工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#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;
}


这将通过检查无穷大和NaN是否在双重限制范围内来检测Visual Studio中的无穷大和NaN:

1
2
3
4
5
6
//#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;

IEEE标准规定指数为1时和尾数不是零,数字是NaN。double是1个符号位、11个指数位和52个尾数位。做一点检查。


正如上面的评论,状态A!=A在G++和其他一些编译器中不起作用,但是这个技巧应该起作用。它可能没有那么有效,但它仍然是一种方式:

1
2
3
4
5
6
7
bool IsNan(float a)
{
    char s[4];
    sprintf(s,"%.3f", a);
    if (s[0]=='n') return true;
    else return false;
}

基本上,如果变量不是有效的整数/浮点数,那么printf在%d或.f格式上打印"nan"(我不确定其他格式)。因此,此代码检查字符串的第一个字符是否为"n"(如"nan")。