是否存在isnan()函数?

注:我在MinGW(如果这有区别的话)。

我使用isnan()从<math.h>解决了这个问题,这在<cmath>中不存在,我一开始是#包括在内的。


当前回答

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

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

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

其他回答

一个可能的解决方案,不依赖于特定的IEEE表示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) );
}

如上所述,a != a在g++和其他一些编译器中不起作用,但这个技巧应该起作用。它可能没有那么高效,但它仍然是一种方法:

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

基本上,在g++中(虽然我不确定其他)printf在%d或%上打印'nan'。如果变量不是有效的整数/浮点数,则格式为F。因此,这段代码检查字符串的第一个字符是否为“n”(如“nan”)

有三种“正式”的方法:posix isnan宏,c++0x isnan函数模板,或visual c++ _isnan函数。

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

不幸的是,没有可靠的方法来检测是否有IEEE 754表示的nan。标准库提供了一种正式的方法(numeric_limits<double>::is_iec559)。但在实践中,g++之类的编译器会搞砸这一点。

理论上,我们可以简单地使用x != x,但g++和visual c++之类的编译器却搞砸了。

因此,最后,测试特定的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> 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> _

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

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

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

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

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

数字不能同时< 0和>= 0,所以实际上只有当数字既不小于也不大于或等于0时,这个检查才会通过。基本上没有数字,或者NaN。

如果你喜欢,你也可以使用这个:

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

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