检查双精度(或浮点数)是否为 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
Checking if a double (or float) is NaN in C++
提问by hasen
采纳答案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 != f
will 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 cmath
includes 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::isnan
is 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 cmath
or 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::isnan
neither 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
返回值
true
if arg is NaN
, false
otherwise
true
如果 arg 是NaN
,false
否则
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 x
shall 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 NaN
is to use the IEEE 754 property that NaN
is not equal to itself: i.e. x == x
will be false for x
being NaN
.
要检查理应可移植的方法NaN
是使用IEEE 754属性,NaN
不等于本身:即x == x
将是错误的x
是NaN
。
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 isnan
macro, c++0x isnan
function template, or visual c++ _isnan
function.
共有三种“官方”方式: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 limits
standard 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.0
instead.
我对这个问题的回答是不要对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
results from the operation 0.f/0.f
, or 0.0/0.0
. nan
is a terrible nemesis to the stability of your code that must be detected and preventedvery carefully1. The properties of nan
that are different from normal numbers:
nan
操作的结果0.f/0.f
,或0.0/0.0
。 nan
对您的代码的稳定性来说是一个可怕的克星,必须非常小心地检测和防止1。其性质nan
与普通数不同:
nan
is toxic, (5*nan
=nan
)nan
is not equal to anything, not even itself (nan
!=nan
)nan
not greater than anything (nan
!> 0)nan
is 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 nan
number (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 nan
values tend to produce difficult to find bugs. (Note how this is notthe case for inf
or -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
-inf
TRUE
inf
-inf
inf
what to do under nan
在nan下做什么
What you want to happen under 0.0/0.0
must 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.0
to generate HUGE
instead. 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
, inf
would result (which has pretty good/nondestructive behavior as mentioned above actually).
因此,在上面,如果 x 是0.f
,inf
将导致(实际上如上所述具有非常好的/非破坏性行为)。
Remember, integer division by 0 causes a runtime exception. So you must always check for integer division by 0. Just because 0.0/0.0
quietly evaluates to nan
doesn't mean you can be lazy and not check for 0.0/0.0
before it happens.
请记住,整数除以 0 会导致运行时异常。因此,您必须始终检查整数除以 0 的情况。仅仅因为0.0/0.0
安静地评估为nan
并不意味着您可以懒惰并且0.0/0.0
在它发生之前不检查。
1 Checks for nan
via x != x
are sometimes unreliable (x != x
being stripped out by some optimizing compilers that break IEEE compliance, specifically when the -ffast-math
switch is enabled).
1通孔检查有时不可靠(被一些破坏 IEEE 合规性的优化编译器剥离,特别是在启用开关时)。nan
x != x
x != x
-ffast-math