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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/570669/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:00:09  来源:igfitidea点击:

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

c++doublenan

提问by hasen

Is there an isnan() function?

有 isnan() 函数吗?

PS.: I'm in MinGW(if that makes a difference).

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

I had this solved by using isnan() from <math.h>, which doesn't exist in <cmath>, which I was #includeing at first.

我通过使用 isnan() from 解决了这个问题<math.h>,它在 中不存在<cmath>,我最初是这样做的#include

采纳答案by jalf

According to the IEEE standard, NaN values have the odd property that comparisons involving them are alwaysfalse. That is, for a float f, f != fwill be true onlyif f is NaN.

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

Note that, as some comments below have pointed out, not all compilers respect this when optimizing code.

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

For any compiler which claims to use IEEE floating point, this trick shouldwork. But I can't guarantee that it willwork in practice. Check with your compiler, if in doubt.

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

回答by mloskot

There is no isnan()function available in current C++ Standard Library. It was introduced in C99and defined as a macronot a function. Elements of standard library defined by C99 are not part of current C++ standard ISO/IEC 14882:1998 neither its update ISO/IEC 14882:2003.

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

In 2005 Technical Report 1 was proposed. The TR1 brings compatibility with C99 to C++. In spite of the fact it has never been officially adopted to become C++ standard, many (GCC 4.0+or Visual C++ 9.0+C++ implementations do provide TR1 features, all of them or only some (Visual C++ 9.0 does not provide C99 math functions).

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

If TR1 is available, then cmathincludes C99 elements like isnan(), isfinite(), etc. but they are defined as functions, not macros, usually in std::tr1::namespace, though many implementations (i.e. GCC 4+ on Linux or in XCode on Mac OS X 10.5+) inject them directly to std::, so std::isnanis well defined.

如果 TR1 可用,则cmath包括 C99 元素,如isnan(),isfinite()等,但它们被定义为函数,而不是宏,通常在std::tr1::命名空间中,尽管许多实现(即 Linux 上的 GCC 4+ 或 Mac OS X 10.5+ 上的 XCode 中)注入它们直接到std::,所以std::isnan定义明确。

Moreover, some implementations of C++ still make C99 isnan()macro available for C++ (included through cmathor math.h), what may cause more confusions and developers may assume it's a standard behaviour.

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

A note about Viusal C++, as mentioned above, it does not provide std::isnanneither std::tr1::isnan, but it provides an extension function defined as _isnan()which has been available since Visual C++ 6.0

关于 Viusal C++ 的说明,如上所述,它std::isnan既不提供std::tr1::isnan,也提供定义为 的扩展函数_isnan(),自Visual C++ 6.0起可用

On XCode, there is even more fun. As mentioned, GCC 4+ defines std::isnan. For older versions of compiler and library form XCode, it seems (here is relevant discussion), haven't had chance to check myself) two functions are defined, __inline_isnand()on Intel and __isnand()on Power PC.

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

回答by BlueTrin

First solution: if you are using C++11

第一个解决方案:如果您使用的是 C++11

Since this was asked there were a bit of new developments: it is important to know that std::isnan()is part of C++11

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

Synopsis

概要

Defined in header <cmath>

在标题中定义 <cmath>

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

Determines if the given floating point number arg is not-a-number (NaN).

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

Parameters

参数

arg: floating point value

arg: 浮点值

Return value

返回值

trueif arg is NaN, falseotherwise

true如果 arg 是NaNfalse否则

Reference

参考

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

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

Please note that this is incompatible with -fast-math if you use g++, see below for other suggestions.

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



Other solutions: if you using non C++11 compliant tools

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

For C99, in C, this is implemented as a macro isnan(c)that returns an int value. The type of xshall be float, double or long double.

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

Various vendors may or may not include or not a function isnan().

各种供应商可能包含或不包含某个功能isnan()

The supposedly portable way to check for NaNis to use the IEEE 754 property that NaNis not equal to itself: i.e. x == xwill be false for xbeing NaN.

要检查理应可移植的方法NaN是使用IEEE 754属性,NaN不等于本身:即x == x将是错误的xNaN

However the last option may not work with every compiler and some settings (particularly optimisation settings), so in last resort, you can always check the bit pattern ...

然而,最后一个选项可能不适用于每个编译器和某些设置(特别是优化设置),因此在最后的手段中,您始终可以检查位模式......

回答by Anonymous

There is also a header-only librarypresent in Boost that have neat tools to deal with floating point datatypes

Boost 中还有一个只有头文件的库,它有处理浮点数据类型的简洁工具

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

You get the following functions:

您将获得以下功能:

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

If you have time then have a look at whole Math toolkit from Boost, it has many useful tools and is growing quickly.

如果您有时间,请查看 Boost 的整个 Math 工具包,它有许多有用的工具并且正在快速增长。

Also when dealing with floating and non-floating points it might be a good idea to look at the Numeric Conversions.

此外,在处理浮点和非浮点时,查看数字转换可能是个好主意。

回答by Cheers and hth. - Alf

There are three "official" ways: posix isnanmacro, c++0x isnanfunction template, or visual c++ _isnanfunction.

共有三种“官方”方式:posixisnan、c++0xisnan函数模板或visual c++_isnan函数

Unfortunately it's rather impractical to detect which of those to use.

不幸的是,检测要使用哪些是不切实际的。

And unfortunately, there's no reliable way to detect whether you have IEEE 754 representation with NaNs. The standard library offers an official such way (numeric_limits<double>::is_iec559). But in practice compilers such as g++ screw that up.

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

In theory one could use simply x != x, but compilers such as g++ and visual c++ screw that up.

理论上可以简单地使用x != x,但是诸如 g++ 和 Visual c++ 之类的编译器搞砸了。

So in the end, test for the specific NaN bitpatterns, assuming (and hopefully enforcing, at some point!) a particular representation such as IEEE 754.

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



EDIT: as an example of "compilers such as g++ … screw that up", consider

编辑:作为“诸如 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 );
}

Compiling with g++ (TDM-2 mingw32) 4.4.1:

使用 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> _

回答by CTT

There is an std::isnan if you compiler supports c99 extensions, but I'm not sure if mingw does.

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

Here is a small function which should work if your compiler doesn't have the standard function:

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

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

回答by Bill the Lizard

You can use numeric_limits<float>::quiet_NaN( )defined in the limitsstandard library to test with. There's a separate constant defined for double.

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

I don't know if this works on all platforms, as I only tested with g++ on Linux.

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

回答by raimue

You can use the isnan()function, but you need to include the C math library.

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

#include <cmath>

As this function is part of C99, it is not available everywhere. If your vendor does not supply the function, you can also define your own variant for compatibility.

由于此功能是 C99 的一部分,因此并非随处可用。如果您的供应商不提供该功能,您也可以定义自己的变体以实现兼容性。

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

回答by Ian

The following code uses the definition of NAN (all exponent bits set, at least one fractional bit set) and assumes that sizeof(int) = sizeof(float) = 4. You can look up NAN in Wikipedia for the details.

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

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

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

回答by bobobobo

nan prevention

预防

My answer to this question is don't use retroactive checks for nan. Use preventivechecks for divisions of the form 0.0/0.0instead.

我对这个问题的回答是不要对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.

nanresults from the operation 0.f/0.f, or 0.0/0.0. nanis a terrible nemesis to the stability of your code that must be detected and preventedvery carefully1. The properties of nanthat are different from normal numbers:

nan操作的结果0.f/0.f,或0.0/0.0nan对您的代码的稳定性来说是一个可怕的克星,必须非常小心地检测和防止1。其性质nan与普通数不同:

  • nanis toxic, (5*nan=nan)
  • nanis not equal to anything, not even itself (nan!= nan)
  • nannot greater than anything (nan!> 0)
  • nanis not less than anything (nan!< 0)
  • nan有毒,(5* nan= nan)
  • nan不等于任何东西,甚至不等于它本身(nan!= nan
  • nan不大于任何东西(nan!> 0)
  • nan不小于任何东西(nan!< 0)

The last 2 properties listed are counter-logical and will result in odd behavior of code that relies on comparisons with a nannumber (the 3rd last property is odd too but you're probably not ever going to see x != x ?in your code (unless you are checking for nan (unreliably))).

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

In my own code, I noticed that nanvalues tend to produce difficult to find bugs. (Note how this is notthe case for infor -inf. (-inf< 0) returns TRUE, ( 0 < inf) returns TRUE, and even (-inf< inf) returns TRUE. So, in my experience, the behavior of the code is oftenstill as desired).

在我自己的代码中,我注意到nan值往往会产生难以发现的错误。(注意or不是这种情况。( < 0) 返回,( 0 < ) 返回 TRUE,甚至 ( < ) 返回 TRUE。因此,根据我的经验,代码的行为通常仍然符合预期)。inf-inf-infTRUEinf-infinf

what to do under nan

在nan下做什么

What you want to happen under 0.0/0.0must be handled as a special case, but what you do must depend on the numbers you expect to come out of the code.

你想要发生的事情0.0/0.0必须作为特殊情况处理,但你做什么必须取决于你期望从代码中得到的数字。

In the example above, the result of (0.f/FLT_MIN) will be 0, basically. You may want 0.0/0.0to generate HUGEinstead. So,

在上面的例子中, ( 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.

So in the above, if x were 0.f, infwould result (which has pretty good/nondestructive behavior as mentioned above actually).

因此,在上面,如果 x 是0.finf将导致(实际上如上所述具有非常好的/非破坏性行为)。

Remember, integer division by 0 causes a runtime exception. So you must always check for integer division by 0. Just because 0.0/0.0quietly evaluates to nandoesn't mean you can be lazy and not check for 0.0/0.0before it happens.

请记住,整数除以 0 会导致运行时异常。因此,您必须始终检查整数除以 0 的情况。仅仅因为0.0/0.0安静地评估为nan并不意味着您可以懒惰并且0.0/0.0在它发生之前不检查。

1 Checks for nanvia x != xare sometimes unreliable (x != xbeing stripped out by some optimizing compilers that break IEEE compliance, specifically when the -ffast-mathswitch is enabled).

1通孔检查有时不可靠(被一些破坏 IEEE 合规性的优化编译器剥离,特别是在启用开关时)。nanx != xx != x-ffast-math