是否存在isnan()函数?

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

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


当前回答

考虑到(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)

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

其他回答

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

2005年提出了技术报告1。TR1为c++带来了与C99的兼容性。尽管它从未被正式采用成为c++标准,但许多实现(GCC 4.0+或Visual c++ 9.0+ c++实现)确实提供了TR1特性,全部或仅部分(Visual c++ 9.0不提供C99数学函数)。

如果TR1可用,那么cmath包含C99元素,如isnan(), isfinite()等,但它们被定义为函数,而不是宏,通常在std:: TR1:: namespace中,尽管许多实现(例如Linux上的GCC 4+或Mac OS X 10.5+上的XCode)将它们直接注入std::,因此std::isnan定义良好。

此外,c++的一些实现仍然使C99 isnan()宏对c++可用(通过cmath或math.h包含),这可能会引起更多的混淆,开发人员可能认为这是一种标准行为。

关于visualc++的一个注意事项,如上所述,它不提供std::isnan,也不提供std::tr1::isnan,但它提供了一个定义为_isnan()的扩展函数,该扩展函数自visualc++ 6.0以来一直可用

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

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

//#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;

如上所述,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”)

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

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

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

根据IEEE标准,NaN值有一个奇怪的性质,涉及它们的比较总是假的。也就是说,对于浮点数f, f != f只有在f为NaN时才为真。

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

对于任何声称使用IEEE浮点数的编译器,这个技巧都应该有效。但我不能保证它在实践中会起作用。如果有疑问,请检查编译器。