答案 0 :(得分:333)
根据IEEE标准,NaN值具有奇怪的属性,即涉及它们的比较总是 false。也就是说,对于浮点数f,如果f是NaN,则f != f
将仅为 。
请注意,正如下面的一些评论所指出的,并非所有编译器在优化代码时都会尊重这一点。
对于声称使用IEEE浮点的任何编译器,此技巧应工作。但我无法保证将在实践中发挥作用。如果有疑问,请咨询您的编译器。
答案 1 :(得分:216)
当前的C ++标准库中没有isnan()
函数可用。它是在C99中引入的,并定义为macro而不是函数。由C99定义的标准库的元素不是当前C ++标准ISO / IEC 14882:1998的一部分,也不是其更新ISO / IEC 14882:2003。
2005年提出了技术报告1。 TR1带来了与C99到C ++的兼容性。尽管事实上它从未被正式采用成为C ++标准,但许多(GCC 4.0+或Visual C++ 9.0+ C ++实现确实提供了TR1功能,所有这些功能或者只有一些(Visual C ++ 9.0不提供C99)数学函数)。
如果TR1可用,则cmath
包含isnan()
,isfinite()
等C99元素,但它们被定义为函数,而不是宏,通常位于std::tr1::
命名空间中虽然许多实现(即Linux上的GCC 4+或Mac OS X 10.5+上的XCode)直接将它们注入std::
,因此std::isnan
已明确定义。
此外,C ++的一些实现仍然使C99 isnan()
宏可用于C ++(包括cmath
或math.h
),这可能会导致更多的混淆,开发人员可能会认为它是标准行为
关于Viusal C ++的注释,如上所述,它不提供std::isnan
std::tr1::isnan
,但它提供了一个定义为_isnan()
的扩展函数,该函数自{{3}起可用}}
在XCode上,还有更多乐趣。如上所述,GCC 4+定义std::isnan
。对于旧版本的编译器和库形式的XCode,似乎(这里是Visual C++ 6.0),没有机会检查自己)定义了两个函数,__inline_isnand()
在英特尔和__isnand()
上Power PC。
答案 2 :(得分:151)
因为有人提出了一些新的发展:重要的是要知道std::isnan()
是C ++ 11的一部分
在标题<cmath>
bool isnan( float arg ); (since C++11)
bool isnan( double arg ); (since C++11)
bool isnan( long double arg ); (since C++11)
确定给定的浮点数arg是否不是数字(NaN
)。
<强>参数强>
arg
:浮点值
返回值
true
如果arg是NaN
,则false
<强>参考强>
http://en.cppreference.com/w/cpp/numeric/math/isnan
请注意,如果您使用g ++,这与-fast-math不兼容,请参阅下面的其他建议。
对于C99,在C中,这被实现为返回int值的宏isnan(c)
。 x
的类型应为float,double或long double。
各种供应商可能包括也可能不包含功能isnan()
。
检查NaN
的所谓可移植方式是使用NaN
不等于自身的IEEE 754属性:x == x
将为x
为假NaN
。
但是最后一个选项可能不适用于每个编译器和一些设置(特别是优化设置),所以最后,你可以随时检查位模式......
答案 3 :(得分:82)
Boost中还有一个header-only library,它具有处理浮点数据类型的简洁工具
#include <boost/math/special_functions/fpclassify.hpp>
您将获得以下功能:
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);
如果你有时间看看Boost的整个Math工具包,它有很多有用的工具,而且发展很快。
同样在处理浮点和非浮点时,最好查看Numeric Conversions。
答案 4 :(得分:43)
有三种“官方”方式:posix isnan
宏,c ++ 0x isnan
功能模板,或visual c ++ _isnan
功能。
不幸的是,检测哪些使用它是相当不切实际的。
不幸的是,没有可靠的方法来检测您是否使用NaN进行IEEE 754表示。标准库以官方方式提供(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> _
答案 5 :(得分:38)
如果编译器支持c99扩展,那么有一个std :: isnan,但我不确定mingw是否支持。
如果您的编译器没有标准函数,这是一个小函数:
bool custom_isnan(double var)
{
volatile double d = var;
return d != d;
}
答案 6 :(得分:25)
您可以使用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;
}
我不知道这是否适用于所有平台,因为我只在Linux上使用g ++进行过测试。
答案 7 :(得分:17)
您可以使用isnan()
功能,但需要包含C数学库。
#include <cmath>
由于此功能是C99的一部分,因此无法在任何地方使用。如果您的供应商不提供该功能,您还可以定义自己的变体以实现兼容性。
inline bool isnan(double x) {
return x != x;
}
答案 8 :(得分:12)
我对此问题的回答是不要对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
来自操作0.f/0.f
或0.0/0.0
。 nan
对于代码的稳定性是一个可怕的克星,必须检测并防止非常小心 1 。 nan
的属性与正常数字不同:
nan
有毒,(5 * nan
= nan
)nan
不等于任何东西,甚至不是自己(nan
!= nan
)nan
不大于任何内容(nan
!&gt; 0)nan
不小于任何内容(nan
!&lt; 0)列出的最后两个属性是反逻辑的,会导致代码的奇怪行为依赖于与nan
数字的比较(第三个属性也很奇怪,但你可能永远不会看到代码中x != x ?
(除非您正在检查nan(不可靠))。)
在我自己的代码中,我注意到nan
值往往会产生难以发现的错误。 (请注意inf
或-inf
的情况不。(-inf
&lt; 0)返回TRUE
,(0&lt; { {1}})返回TRUE,偶数(inf
&lt; -inf
)返回TRUE。因此,根据我的经验,代码的行为经常仍然是所希望的)。
您希望在inf
下实现的内容必须作为特殊情况处理,但您所做的事情必须取决于您希望从代码中获得的数字。
在上面的示例中,(0.0/0.0
)的结果基本上是0.f/FLT_MIN
。您可能希望0
生成0.0/0.0
。所以,
HUGE
因此,在上文中,如果x为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.
,则会产生0.f
(实际上具有相当好/非破坏性的行为)。
请记住,integer division by 0 causes a runtime exception。因此,您必须始终检查整数除以0.只是因为inf
悄然评估为0.0/0.0
并不意味着您可能会懒惰而不会在nan
发生之前检查它。
1 通过0.0/0.0
检查nan
有时不可靠(x != x
被一些违反IEEE合规性的优化编译器剥离,特别是在x != x
切换时已启用)。
答案 9 :(得分:11)
以下代码使用NAN的定义(所有指数位集,至少一个小数位集)并假设sizeof(int)= sizeof(float)= 4.您可以在维基百科中查找NAN以获取详细信息。
bool IsNan( float value )
{
return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000;
}
答案 10 :(得分:7)
inline bool IsNan(float f)
{
const uint32 u = *(uint32*)&f;
return (u&0x7F800000) == 0x7F800000 && (u&0x7FFFFF); // Both NaN and qNan.
}
inline bool IsNan(double d)
{
const uint64 u = *(uint64*)&d;
return (u&0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && (u&0xFFFFFFFFFFFFFULL);
}
如果sizeof(int)
为4且sizeof(long long)
为8,则此方法有效。
在运行期间,它只是比较,铸件不需要任何时间。它只是更改比较标志配置以检查相等性。
答案 11 :(得分:7)
从C ++ 14开始,有许多方法可以测试浮点数value
是否为NaN。
在这些方式中,只有检查数字表示的位,
如我原来的答案所述,可靠地运作。特别是std::isnan
和经常提出的检查v != v
,不能可靠地运行,不应该使用,以免当某人决定需要浮点优化时代码停止正常工作,并要求编译器去做。这种情况可能会发生变化,编译器可以更加符合要求,但是对于这个问题,这个问题在最初答案后的6年内没有发生过。
大约6年来,我原来的答案就是这个问题的选择解决方案,这很好。但最近选择了推荐不可靠v != v
测试的高度赞成的答案。因此,这个额外的更新的答案(我们现在有C ++ 11和C ++ 14标准,C ++ 17即将出现)。
从C ++ 14开始,检查NaN-ness的主要方法是:
std::isnan(value) )
是自C ++ 11以来的标准库。 isnan
显然与此有冲突
Posix宏名称相同,但实际上并不是问题。主要问题是
当请求浮点算术优化时,然后使用至少一个主编译器,即g ++,std::isnan
为NaN参数返回false
。
(fpclassify(value) == FP_NAN) )
遇到与std::isnan
相同的问题,即不可靠。
(value != value) )
在许多SO答案推荐。遇到与std::isnan
相同的问题,即
不可靠。
(value == Fp_info::quiet_NaN()) )
这是一个测试,标准行为不应该检测NaNs,而是检测NaNs
优化的行为可能会检测到NaN(由于优化的代码只是比较
直接的bitlevel表示),也许与另一种方式相结合
覆盖标准的未优化行为,可以可靠地检测NaN。不幸
结果证明不能可靠地工作。
(ilogb(value) == FP_ILOGBNAN) )
遇到与std::isnan
相同的问题,即不可靠。
isunordered(1.2345, value) )
遇到与std::isnan
相同的问题,即不可靠。
is_ieee754_nan( value ) )
这不是标准功能。它根据IEEE 754检查位
标准。它完全可靠但代码在某种程度上取决于系统。
在下面的完整测试代码中,“成功”是表达式是否报告值的纳米。对于大多数表达式而言,这种成功度量,检测NaNs和仅NaNs的目标,对应于它们的标准语义。但是,对于(value == Fp_info::quiet_NaN()) )
表达式,标准行为是它不能用作NaN检测器。
#include <cmath> // std::isnan, std::fpclassify
#include <iostream>
#include <iomanip> // std::setw
#include <limits>
#include <limits.h> // CHAR_BIT
#include <sstream>
#include <stdint.h> // uint64_t
using namespace std;
#define TEST( x, expr, expected ) \
[&](){ \
const auto value = x; \
const bool result = expr; \
ostringstream stream; \
stream << boolalpha << #x " = " << x << ", (" #expr ") = " << result; \
cout \
<< setw( 60 ) << stream.str() << " " \
<< (result == expected? "Success" : "FAILED") \
<< endl; \
}()
#define TEST_ALL_VARIABLES( expression ) \
TEST( v, expression, true ); \
TEST( u, expression, false ); \
TEST( w, expression, false )
using Fp_info = numeric_limits<double>;
inline auto is_ieee754_nan( double const x )
-> bool
{
static constexpr bool is_claimed_ieee754 = Fp_info::is_iec559;
static constexpr int n_bits_per_byte = CHAR_BIT;
using Byte = unsigned char;
static_assert( is_claimed_ieee754, "!" );
static_assert( n_bits_per_byte == 8, "!" );
static_assert( sizeof( x ) == sizeof( uint64_t ), "!" );
#ifdef _MSC_VER
uint64_t const bits = reinterpret_cast<uint64_t const&>( x );
#else
Byte bytes[sizeof(x)];
memcpy( bytes, &x, sizeof( x ) );
uint64_t int_value;
memcpy( &int_value, bytes, sizeof( x ) );
uint64_t const& bits = int_value;
#endif
static constexpr uint64_t sign_mask = 0x8000000000000000;
static constexpr uint64_t exp_mask = 0x7FF0000000000000;
static constexpr uint64_t mantissa_mask = 0x000FFFFFFFFFFFFF;
(void) sign_mask;
return (bits & exp_mask) == exp_mask and (bits & mantissa_mask) != 0;
}
auto main()
-> int
{
double const v = Fp_info::quiet_NaN();
double const u = 3.14;
double const w = Fp_info::infinity();
cout << boolalpha << left;
cout << "Compiler claims IEEE 754 = " << Fp_info::is_iec559 << endl;
cout << endl;;
TEST_ALL_VARIABLES( std::isnan(value) ); cout << endl;
TEST_ALL_VARIABLES( (fpclassify(value) == FP_NAN) ); cout << endl;
TEST_ALL_VARIABLES( (value != value) ); cout << endl;
TEST_ALL_VARIABLES( (value == Fp_info::quiet_NaN()) ); cout << endl;
TEST_ALL_VARIABLES( (ilogb(value) == FP_ILOGBNAN) ); cout << endl;
TEST_ALL_VARIABLES( isunordered(1.2345, value) ); cout << endl;
TEST_ALL_VARIABLES( is_ieee754_nan( value ) );
}
使用g ++的结果(再次注意(value == Fp_info::quiet_NaN())
的标准行为是它不能用作NaN检测器,这只是非常实际的兴趣):
[C:\my\forums\so\282 (detect NaN)] > g++ --version | find "++" g++ (x86_64-win32-sjlj-rev1, Built by MinGW-W64 project) 6.3.0 [C:\my\forums\so\282 (detect NaN)] > g++ foo.cpp && a Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = true Success u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 0x0100)) = true Success u = 3.14, ((fpclassify(value) == 0x0100)) = false Success w = inf, ((fpclassify(value) == 0x0100)) = false Success v = nan, ((value != value)) = true Success u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success w = inf, ((value == Fp_info::quiet_NaN())) = false Success v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success v = nan, (isunordered(1.2345, value)) = true Success u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:\my\forums\so\282 (detect NaN)] > g++ foo.cpp -ffast-math && a Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = false FAILED u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 0x0100)) = false FAILED u = 3.14, ((fpclassify(value) == 0x0100)) = false Success w = inf, ((fpclassify(value) == 0x0100)) = false Success v = nan, ((value != value)) = false FAILED u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = true Success u = 3.14, ((value == Fp_info::quiet_NaN())) = true FAILED w = inf, ((value == Fp_info::quiet_NaN())) = true FAILED v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success v = nan, (isunordered(1.2345, value)) = false FAILED u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:\my\forums\so\282 (detect NaN)] > _
Visual C ++的结果:
[C:\my\forums\so\282 (detect NaN)] > cl /nologo- 2>&1 | find "++" Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23725 for x86 [C:\my\forums\so\282 (detect NaN)] > cl foo.cpp /Feb && b foo.cpp Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = true Success u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 2)) = true Success u = 3.14, ((fpclassify(value) == 2)) = false Success w = inf, ((fpclassify(value) == 2)) = false Success v = nan, ((value != value)) = true Success u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success w = inf, ((value == Fp_info::quiet_NaN())) = false Success v = nan, ((ilogb(value) == 0x7fffffff)) = true Success u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED v = nan, (isunordered(1.2345, value)) = true Success u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:\my\forums\so\282 (detect NaN)] > cl foo.cpp /Feb /fp:fast && b foo.cpp Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = true Success u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 2)) = true Success u = 3.14, ((fpclassify(value) == 2)) = false Success w = inf, ((fpclassify(value) == 2)) = false Success v = nan, ((value != value)) = true Success u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success w = inf, ((value == Fp_info::quiet_NaN())) = false Success v = nan, ((ilogb(value) == 0x7fffffff)) = true Success u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED v = nan, (isunordered(1.2345, value)) = true Success u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:\my\forums\so\282 (detect NaN)] > _
总结上述结果,只使用本测试程序中定义的is_ieee754_nan
函数直接测试位级表示,在g ++和Visual C ++的所有情况下都能可靠地工作。
附录:
在发布上述内容之后,我意识到还有另一种可能来测试NaN,这里提到another answer,即((value < 0) == (value >= 0))
。事实证明,使用Visual C ++可以正常工作,但是使用g ++的-ffast-math
选项失败了。只有直接的位模式测试才能可靠地工作。
答案 12 :(得分:4)
至于我,解决方案可能是一个宏,使其明确内联,因此足够快。 它也适用于任何浮动类型。它基于这样一个事实:当值不是一个数字时,唯一的情况是当值不是数字时。
#ifndef isnan
#define isnan(a) (a != a)
#endif
答案 13 :(得分:4)
可能的解决方案不依赖于使用的NaN的特定IEEE表示形式如下:
template<class T>
bool isnan( T f ) {
T _nan = (T)0.0/(T)0.0;
return 0 == memcmp( (void*)&f, (void*)&_nan, sizeof(T) );
}
答案 14 :(得分:4)
考虑到(x!= x)并不总是保证NaN(例如,如果使用-ffast-math选项),我一直在使用:
#define IS_NAN(x) (((x) < 0) == ((x) >= 0))
数字不能同时为&lt; 0和&gt; = 0,所以如果数字既不小于,也不大于或等于零,则该检查才会通过。基本上没有数字,或NaN。
如果您愿意,也可以使用此功能:
#define IS_NAN(x) (!((x)<0) && !((x)>=0)
我不确定这会受到-ffast-math的影响,所以你的里程可能会有所不同。
答案 15 :(得分:3)
这有效:
#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
答案 16 :(得分:1)
在我看来,最好的跨平台方法是使用union并测试double的位模式以检查NaN。
我还没有彻底测试过这个解决方案,并且可能有一种更有效的方式来处理位模式,但我认为它应该可行。
$ curl http://localhost:9015/resources/1 --verbose
* Trying ::1...
* Connected to localhost (::1) port 9015 (#0)
> GET /resources/1 HTTP/1.1
> User-Agent: curl/7.41.0
> Host: localhost:9015
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sat, 08 Oct 2016 17:10:11 GMT
< Content-Type: application/json;charset=UTF-8
< Content-Length: 0
<
* Connection #0 to host localhost left intact
答案 17 :(得分:0)
IEEE标准说 当指数全是1时 和 尾数不为零, 这个数字是NaN。 Double是1个符号位,11个指数位和52个尾数位。 做一点检查。
答案 18 :(得分:0)
这可以通过检查是否在双倍限制内来检测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;
答案 19 :(得分:0)
在x86-64上,您可以使用非常快速的方法来检查NaN和无穷大,而无论-ffast-math
编译器选项如何,它们都可以使用。 ({f != f
,std::isnan
,std::isinf
总是用false
产生-ffast-math
)。
可以通过检查最大指数轻松地测试NaN,无穷大和有限数。无穷大是尾数为零的最大指数,NaN是最大指数且尾数为非零。指数存储在最高符号位之后的下一个位中,因此我们只需左移即可去除符号位并使指数成为最高位,而无需进行掩码(operator&
):>
static inline uint64_t load_ieee754_rep(double a) {
uint64_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movq instruction.
return r;
}
static inline uint32_t load_ieee754_rep(float a) {
uint32_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movd instruction.
return r;
}
constexpr uint64_t inf_double_shl1 = UINT64_C(0xffe0000000000000);
constexpr uint32_t inf_float_shl1 = UINT32_C(0xff000000);
// The shift left removes the sign bit. The exponent moves into the topmost bits,
// so that plain unsigned comparison is enough.
static inline bool isnan2(double a) { return load_ieee754_rep(a) << 1 > inf_double_shl1; }
static inline bool isinf2(double a) { return load_ieee754_rep(a) << 1 == inf_double_shl1; }
static inline bool isfinite2(double a) { return load_ieee754_rep(a) << 1 < inf_double_shl1; }
static inline bool isnan2(float a) { return load_ieee754_rep(a) << 1 > inf_float_shl1; }
static inline bool isinf2(float a) { return load_ieee754_rep(a) << 1 == inf_float_shl1; }
static inline bool isfinite2(float a) { return load_ieee754_rep(a) << 1 < inf_float_shl1; }
std
和isinf
的{{1}}版本从isfinite
段中加载2个double/float
常量,在最坏的情况下,它们可能导致2次数据高速缓存未命中。以上版本不加载任何数据,.data
和inf_double_shl1
常量被编码为汇编指令中的立即操作数。
更快inf_float_shl1
只是2条汇编指令:
isnan2
使用以下事实:如果任何参数为NaN,则ucomisd
指令会设置奇偶校验标志。没有指定bool isnan2(double a) {
bool r;
asm(".intel_syntax noprefix"
"\n\t ucomisd %1, %1"
"\n\t setp %b0"
"\n\t .att_syntax prefix"
: "=g" (r)
: "x" (a)
: "cc"
);
return r;
}
选项时,std::isnan
就是这样工作的。
答案 20 :(得分:-3)
正如上面的评论所述:!= 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或%.f格式上打印'nan'。因此,此代码检查字符串的第一个字符为'n'(如“nan”)