是否存在isnan()函数?

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

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


当前回答

这可以在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;

其他回答

如此:

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

输出:isnan

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

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

有三种“正式”的方法: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> _

当前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()。

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