在C ++中检查双精度(或浮点数)是否为NaN

是否有一个isnan()函数?

PS:我在MinGW (如果这有所作为 )。

我通过使用来自<math.h> isnan()解决了这个问题,它并不存在于<cmath> ,我首先是#include

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

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

对于声称使用IEEE浮点的任何编译器来说,这个技巧应该是可行的。 但是我不能保证它在实践中起作用。 如果有疑问,请咨询您的编译器。

当前的C ++标准库中没有isnan()函数可用。 它在C99中被引入,并被定义为macros而不是函数。 由C99定义的标准库的元素不是当前C ++标准ISO / IEC 14882:1998的一部分,也不是ISO / IEC 14882:2003的更新。

2005年技术报告1被提出。 TR1将C99兼容到C ++。 尽pipe事实上它从来没有被正式采用成为C ++标准,但许多( GCC 4.0+或Visual C ++ 9.0 + C ++实现都提供TR1特性,所有这些特性或者只有一些特性(Visual C ++ 9.0不提供C99math函数) 。

如果TR1可用,那么cmath包括C99元素,如isnan()isfinite()等,但它们被定义为函数,而不是macros,通常在std::tr1:: namespace中,尽pipe许多实现(即GCC 4+ Linux或XCode在Mac OS X 10.5 +)直接注入到std:: ,所以std::isnan定义。

此外,C ++的某些实现仍然使得C99 isnan()macros可用于C ++(通过cmathmath.h包含),可能导致更多混淆,开发人员可能会认为这是一种标准行为。

关于Viusal C ++的说明,如上所述,它不提供std::isnan既不是std::tr1::isnan ,但它提供了一个扩展函数定义为_isnan() ,自Visual C ++ 6.0

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

第一个解决scheme:如果你正在使用C ++ 11

由于这个问题有一些新的发展:重要的是要知道std::isnan()是C ++ 11的一部分

概要

在头文件<cmath>定义

 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否则返回false

参考

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

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


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

对于C99,在C中,这是作为返回int值的macrosisnan(c)实现的。 x的types应为float,double或long double。

各种供应商可能会或可能不会包含或不包含isnan()函数。

假设可移植的方法来检查NaN是使用NaN不等于自己的IEEE 754属性:即x == x将为false,因为xNaN

然而,最后一个选项可能不适用于每个编译器和一些设置(特别是优化设置),所以在最后的手段,你总是可以检查位模式…

在Boost中还有一个只包含头文件的库 ,它有整洁的工具来处理浮点数据types

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

你得到以下function:

 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的整个math工具包,它有很多有用的工具,并且正在快速增长。

另外,当处理浮点和非浮点时,查看数值转换可能是一个好主意。

有三种“官方”方式:posix isnanmacros ,c ++ 0x isnan函数模板 ,或visual c ++ _isnan函数

不幸的是,检测那些使用哪一个是不切实际的。

不幸的是,没有可靠的方法来检测您是否具有NaN的IEEE 754表示。 标准库提供了一个官方的方式( numeric_limits<double>::is_iec559 )。 但在实践编译器,如g ++螺丝起来。

理论上可以简单地使用x != x ,但编译器(如g ++和visual c ++)则可以使用它。

所以最后,testing特定的NaN位模式 ,假设(并希望在某个时候强制执行)特定的表示,如IEEE 754。


编辑 :作为“编译器,如g ++的…螺丝起来”的例子,考虑

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

用g ++编译(TDM-2 mingw32)4.4.1:

 C:\ test>键入“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作品... || 回声!失败
作品...

 C:\ test> gnuc x.cpp  - 快速math

 C:\ test> a && echo作品... || 回声!失败
断言失败:a!= b,文件x.cpp,第6行

这个应用程序已经请求运行时以不寻常的方式终止它。
请联系应用程序的支持团队获取更多信息。
 !失败

 C:\ test> _

有一个std :: isnan,如果你的编译器支持c99扩展,但我不确定是否是mingw。

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

 bool custom_isnan(double var) { volatile double d = var; return d != d; } 

您可以使用limits标准库中定义的numeric_limits<float>::quiet_NaN( )来testing。 有一个单独的常量定义为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; } 

我不知道这是否适用于所有平台,因为我只在Linux上使用g ++进行testing。

你可以使用isnan()函数,但是你需要包含Cmath库。

 #include <cmath> 

由于此function是C99的一部分,因此无法在任何地方使用。 如果您的供应商不提供该function,您还可以定义您自己的变体的兼容性。

 #ifndef isnan inline bool isnan(double x) { return x != x; } #endif 

下面的代码使用NAN的定义(所有指数位集,至less一个小数位集),并假定sizeof(int)= sizeof(float)= 4。您可以在维基百科中查找NAN以获取详细信息。

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

预防

我对这个问题的回答是不要使用追溯检查nan 。 改为使用0.0/0.0格式的分隔预防性检查。

 #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结果来自0.f/0.f0.0/0.0nan是一个可怕的克星你的代码的稳定性,必须非常仔细地检测和防止 1nan的属性与正常数字不同:

  • nan是有毒的,(5 * nan = nan
  • nan不等于任何东西,甚至不是本身( nan != nan
  • nan不超过任何东西( nan !> 0)
  • nan不低于任何东西( nan !<0)

列出的最后2个属性是反逻辑的,并且会导致依赖与nan数进行比较的代码的奇怪行为(最后的第3个属性也是奇怪的,但是您可能从未在您的系统中看到x != x ?代码(除非你正在检查nan(不可靠)))。

在我自己的代码中,我注意到nan值往往会产生很难find的错误。 (注意inf-inf的情况并不是这样( -inf <0)返回TRUE ,(0 < inf )返回TRUE,甚至( -inf < inf )返回TRUE,所以根据我的经验,的代码通常仍然按照需要)。

nan下怎么办?

你想在0.0/0.0发生的事情必须作为一个特例来处理 ,但是你所做的必须取决于你期望从代码中得到的数字。

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

 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会导致运行时exception 。 所以你必须经常检查整数除0.只是因为0.0/0.0安静地评估到nan并不意味着你可以懒惰,不检查0.0/0.0之前发生。

1 检查nan通过x != x有时是不可靠的( x != x被某些优化编译器剥离,这些优化编译器会中断IEEE符合性,尤其是当启用了-ffast-math开关时)。

 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,这是有效的。

运行期间只是比较,铸件不需要任何时间。 它只是改变比较标志configuration来检查相等性。

一个可能的解决scheme,将不依赖于具体的电气和电子工程师学会使用的NaN表示如下:

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

至于我的解决scheme可能是一个macros,使其明确内联,从而足够快。 它也适用于任何浮点types。 它基于这样一个事实,即当一个值不等于自身的唯一情况是这个值不是一个数字时。

 #ifndef isnan #define isnan(a) (a != a) #endif 

在阅读了其他答案之后,我想要一些能够通过浮点比较警告的东西,并且不会在快速math下破坏。 下面的代码似乎工作:

 /* Portable warning-free NaN test: * Does not emit warning with -Wfloat-equal (does not use float comparisons) * Works with -O3 -ffast-math (floating-point optimization) * Only call to standard library is memset and memcmp via <cstring> * Works for IEEE 754 compliant floating-point representations * Also works for extended precision long double */ #include <cstring> template <class T> bool isNaN(T x) { /*Initialize all bits including those used for alignment to zero. This sets all the values to positive zero but does not clue fast math optimizations as to the value of the variables.*/ T z[4]; memset(z, 0, sizeof(z)); z[1] = -z[0]; z[2] = x; z[3] = z[0] / z[2]; /*Rationale for following test: * x is 0 or -0 --> z[2] = 0, z[3] = NaN * x is a negative or positive number --> z[3] = 0 * x is a negative or positive denormal number --> z[3] = 0 * x is negative or positive infinity --> z[3] = 0 (IEEE 754 guarantees that 0 / inf is zero) * x is a NaN --> z[3] = NaN != 0. */ //Do a bitwise comparison test for positive and negative zero. bool z2IsZero = memcmp(&z[2], &z[0], sizeof(T)) == 0 || memcmp(&z[2], &z[1], sizeof(T)) == 0; bool z3IsZero = memcmp(&z[3], &z[0], sizeof(T)) == 0 || memcmp(&z[3], &z[1], sizeof(T)) == 0; //If the input is bitwise zero or negative zero, then it is not NaN. return !z2IsZero && !z3IsZero; } //NaN test suite #include <iostream> /*If printNaN is true then only expressions that are detected as NaN print and vice versa.*/ template <class T> void test(bool printNaN) { T v[10] = {-0.0, 0.0, -1.0, 1.0, std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), std::numeric_limits<T>::denorm_min(), -std::numeric_limits<T>::denorm_min(), std::numeric_limits<T>::quiet_NaN(), std::numeric_limits<T>::signaling_NaN()}; for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) { if(isNaN(v[i] + v[j]) == printNaN) std::cout << v[i] << "+" << v[j] << " = " << v[i] + v[j] << std::endl; if(isNaN(v[i] - v[j]) == printNaN) std::cout << v[i] << "-" << v[j] << " = " << v[i] - v[j] << std::endl; if(isNaN(v[i] * v[j]) == printNaN) std::cout << v[i] << "*" << v[j] << " = " << v[i] * v[j] << std::endl; if(isNaN(v[i] / v[j]) == printNaN) std::cout << v[i] << "/" << v[j] << " = " << v[i] / v[j] << std::endl; } } } //Test each floating-point type. int main() { std::cout << "NaNs:" << std::endl; test<float>(true); test<double>(true); test<long double>(true); std::cout << std::endl << "Not NaNs:" << std::endl; test<float>(false); test<double>(false); test<long double>(false); return 0; } 

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

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

数字不能都是<0和> = 0,所以如果数字不小于,也不大于或等于零,那么这个检查只能通过。 基本上没有数字,或NaN。

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

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

虽然我不确定这是怎么影响的,所以你的里程可能会有所不同。

从C ++ 14开始,有许多方法可以testing浮点数value是否为NaN。

在这些方法中,只有检查数字表示的位 ,才能可靠地工作,正如我原来的回答中所指出的那样。 特别是, std::isnan和经常提出的检查v != v ,不能可靠地工作,不应该被使用,否则当有人决定需要浮点优化时,代码将停止正常工作,并要求编译器这样做。 这种情况可以改变,编译人员可以得到更多的符合,但对于原来的答复6年以来没有发生过的这个问题。

大约6年来,我的原始答案是这个问题的select的解决scheme,这是确定的。 但是最近select了一个推荐不可靠的v != vtesting的高回报的答案。 因此,这个额外的更新的答案(我们现在有C + + 11和C + + 14标准,C + + 17在地平线上)。


从C ++ 14开始,检查NaN-ness的主要方法是:

  • std::isnan(value) )
    是自C ++ 11以来预期的标准库方法。 isnan显然与同名的Posixmacros冲突,但实际上这不是问题。 主要的问题是,当请求浮点算术优化时,至less有一个主编译器,即g ++, std::isnan 为NaN参数返回false

  • (fpclassify(value) == FP_NAN) )
    患有与std::isnan相同的问题,即不可靠。

  • (value != value) )
    build议在许多SO答案。 患有与std::isnan相同的问题,即不可靠。

  • (value == Fp_info::quiet_NaN()) )
    这是一个testing,标准的行为不应该检测NaNs,但是与优化的行为可能可以检测NaNs(由于优化的代码只是比较直接比特级表示),也许结合另一种方式来覆盖标准的未优化的行为,可以可靠地检测到NaN。 不幸的是,结果不能可靠地工作。

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

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

  • is_ieee754_nan( value ) )
    这不是一个标准function。 它根据IEEE 754标准检查比特。 这是完全可靠的, 代码是有点系统相关的。


在下面的完整的testing代码中,“成功”是expression式是否报告了值的南北。 对于大多数expression式来说,这种成功的衡量标准,检测NaNs和NaNs的目标与他们的标准语义是一致的。 但是,对于(value == Fp_info::quiet_NaN()) )expression式,标准行为是它不能用作NaN检测器。

 #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探测器,这只是非常实际的兴趣):

 [C:\ my \ forums \ so \ 282(检测NaN)]
 > g ++ --version |  find“++”
 g ++(x86_64-win32-sjlj-rev1,由MinGW-W64项目构build)6.3.0

 [C:\ my \ forums \ so \ 282(检测NaN)]
 > g ++ foo.cpp && a
编译器声称IEEE 754 = true

 v = nan,(std :: isnan(value))= true成功
 u = 3.14,(std :: isnan(value))= false成功
 w = inf,(std :: isnan(value))= false成功

 v = nan,((fpclassify(value)== 0x0100))= true成功
 u = 3.14,((fpclassify(value)== 0x0100))= false成功
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++.


附录:
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.

这工作:

 #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

The IEEE standard says when exponent is all 1s and 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.

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

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

    Interesting Posts