检查 C++ 中的 double(或 float)是否为 NaN
题
有 isnan() 函数吗?
附:算我一个 明GW (如果这有影响的话)。
我通过使用 isnan() 解决了这个问题 <math.h>
, ,它不存在于 <cmath>
, ,我就是 #include
一开始。
解决方案
根据IEEE标准,NaN值具有奇数属性,涉及它们的比较是总是假。也就是说,浮子楼f != f
将为真仅如果f为NaN。
请注意,如下面一些评论所指出的那样,并不是所有的编译器优化代码时遵守这一。
有关其要求使用IEEE浮点任何编译器,这一招应工作。但我不能保证它的将的工作实践。请与您的编译器,如果有疑问。
其他提示
没有 isnan()
当前 C++ 标准库中提供的函数。它被引入于 C99 并定义为 宏 不是一个函数。C99 定义的标准库元素不是当前 C++ 标准 ISO/IEC 14882:1998 的一部分,也不是其更新版 ISO/IEC 14882:2003 的一部分。
2005年提出了技术报告1。TR1 为 C++ 带来了与 C99 的兼容性。尽管事实上它从未被正式采用成为 C++ 标准,但许多(海湾合作委员会 4.0+ 或者 视觉C++ 9.0+ C++ 实现确实提供 TR1 功能,全部或仅部分功能(Visual C++ 9.0 不提供 C99 数学函数)。
如果 TR1 可用,则 cmath
包括 C99 元素,例如 isnan()
, isfinite()
, , ETC。但它们通常被定义为函数,而不是宏 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()
自此以来一直可用 视觉C++6.0
在 XCode 上,还有更多乐趣。如前所述,GCC 4+ 定义 std::isnan
. 。对于旧版本的编译器和库形式的 XCode,似乎(这里是 相关讨论),还没有机会检查自己)定义了两个函数, __inline_isnand()
关于英特尔和 __isnand()
在 Power PC 上。
首先溶液:如果要使用C ++ 11
由于这是问有一点新的发展:它知道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/数学/ isnan
请注意,如果你使用G ++,请参见下面的其他建议,这是用-fast-数学不兼容。
其他解决方案:如果您使用非C ++ 11个兼容的工具
有关C99,在C,这是这样实现的isnan(c)
that返回int值的宏。类型x
的应是浮点,双或双长
各种供应商可以或可以不包括或不函数isnan()
。
以检查NaN
据推测是可移植的方法是使用NaN
不等于本身IEEE 754性质:即x == x
将是x
是NaN
假
但是最后的选项可能无法与每一个编译器和一些设置(特别优化设置)工作,所以在最后的手段,可以随时查询位模式...
还有一个 仅标头库 Boost 中提供了处理浮点数据类型的简洁工具
#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 的整个数学工具包,它有很多有用的工具,而且增长很快。
此外,在处理浮点和非浮点时,查看一下可能是个好主意 数字转换.
有三个 “正式” 的方法:POSIX的 isnan
宏下,C ++ 0X的 isnan
函数模板下,或Visual C ++的 _isnan
功能即可。
不幸的是这是相当不实用的,以检测要使用的那些。
和遗憾的是,检测到您是否有NaN的IEEE 754表示没有可靠的方法。标准库提供了一个官方这样的方式(numeric_limits<double>::is_iec559
)。但在实践中编译器,如克++螺钉,高达。
在理论上人们可以使用简单的 x != x
,但编译器,如克++和Visual C ++螺钉,高达。
因此,在结束时,用于测试的特定的的NaN bitpatterns 下,假设(希望执行,在某些时候!)特定表示如IEEE 754。
修改强>:作为一个例子 “编译器,如克++ ...螺钉向上”,考虑
#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> _
有是的std :: isnan如果编译器支持C99的扩展,但我不知道,如果做的MinGW
下面是如果你的编译器不具有的标准功能应该工作的一个小功能:
bool custom_isnan(double var)
{
volatile double d = var;
return d != d;
}
可以使用在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 ++测试。
您可以使用isnan()
功能,但你需要包括C数学库。
#include <cmath>
由于此函数是C99的一部分,它是不可用无处不在。如果你的供应商没有提供的功能,您还可以定义自己的兼容性变种。
inline bool isnan(double x) {
return x != x;
}
南预防
我对这个问题的回答是 不要使用追溯检查 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
!> 0)nan
不小于任何东西(nan
!< 0)
列出的最后 2 个属性是反逻辑的,将导致依赖于与 nan
数字(最后第三个属性也很奇怪,但你可能永远不会看到 x != x ?
在你的代码中(除非你正在检查 nan (不可靠)))。
在我自己的代码中,我注意到 nan
值往往会产生难以发现的错误。(注意这是如何 不是 案例为 inf
或者 -inf
. (-inf
< 0) 返回 TRUE
, ( 0 < inf
) 返回 TRUE,甚至 (-inf
< inf
) 返回 TRUE。所以,根据我的经验,代码的行为是 经常 仍如所愿)。
在nan下做什么
您希望在下面发生什么 0.0/0.0
必须作为特殊情况处理, ,但是您所做的必须取决于您期望从代码中得出的数字。
在上面的例子中,(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.
所以在上面,如果 x 是 0.f
, inf
会产生(实际上具有如上所述的相当好的/非破坏性行为)。
记住, 整数除以 0 会导致运行时异常. 。因此,您必须始终检查整数是否除以 0。只是因为 0.0/0.0
静静地评价 nan
并不意味着你可以偷懒而不检查 0.0/0.0
在它发生之前。
1 检查 nan
通过 x != x
有时不可靠(x != x
被一些违反 IEEE 合规性的优化编译器删除,特别是当 -ffast-math
开关已启用)。
下面的代码使用NAN的定义(设置所有指数位,至少一个分数位组),并假设的sizeof(int)的=的sizeof(浮点)= 4。您可以查找在NAN维基百科的细节。
bool IsNan( float value )
{
return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000;
}
从 C++14 开始,有多种方法可以测试浮点数是否 value
是一个 NaN。
这些方法中,只有 检查位 在我原始答案中指出的那样,数字的表示形式可靠。尤其, std::isnan
以及经常提出的检查 v != v
, ,工作不可靠,不应该使用,以免当有人决定需要浮点优化并要求编译器执行此操作时,您的代码将停止正常工作。这种情况可以改变,编译器可以变得更加一致,但对于这个问题来说,自原始答案以来的 6 年里还没有发生过。
大约六年来,我最初的答案是这个问题的选定解决方案,这是可以的。但最近一个高票数的答案推荐了不可靠的 v != v
已选择测试。因此,有了这个额外的更新答案(我们现在有了 C++11 和 C++14 标准,以及即将推出的 C++17)。
从 C++14 开始,检查 NaN 性的主要方法是:
std::isnan(value) )
是自 C++11 以来预期的标准库方式。isnan
显然,与同名的Posix宏有冲突,但实际上这不是问题。主要问题是,当请求浮点算术优化时,然后使用至少一个主编译器,即G ++,std::isnan
回报false
对于 NaN 参数.(fpclassify(value) == FP_NAN) )
遇到同样的问题std::isnan
, ,即不可靠。(value != value) )
在许多 SO 答案中推荐。遇到同样的问题std::isnan
, ,即,不可靠。(value == Fp_info::quiet_NaN()) )
这是一项测试,表明具有标准行为不应检测到NAN,但是通过优化的行为可能可以检测到NAN(由于优化的代码仅直接比较了比特级表示),并且可能与另一种涵盖标准未优化行为的方式相结合,可以可靠地检测到Nan。不幸的是,事实证明它不能可靠地工作。(ilogb(value) == FP_ILOGBNAN) )
遇到同样的问题std::isnan
, ,即不可靠。isunordered(1.2345, value) )
遇到同样的问题std::isnan
, ,即不可靠。is_ieee754_nan( value ) )
这不是标准功能。它根据IEEE 754标准对钻头进行检查。这是完全可靠的 但 该代码在某种程度上依赖于系统。
在下面的完整测试代码中,“成功”是指表达式是否报告值的 Nan-ness。对于大多数表达式来说,这种成功衡量标准(检测 NaN 且仅检测 NaN 的目标)与其标准语义相对应。为了 (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 |查找“ ++” 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 |查找“ ++” Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23725 for x86 [C:\my\forums\so\282 (detect NaN)] > cl foo.cpp /二月 && 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 的方法,在 另一个答案 这里,即 ((value < 0) == (value >= 0))
. 。结果在 Visual C++ 中运行良好,但在 g++ 中失败 -ffast-math
选项。只有直接的位模式测试才能可靠地工作。
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。
在运行时它只有比较,铸件不采取任何时间。它只是改变比较标志配置以检查平等。
这将不依赖于为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) );
}
至于我的解决办法是让它明确内嵌从而足够快的宏。 它也适用于任何float类型。它将根据的事实是唯一的情况下,当一个值不等于本身是当该值不是数字。
#ifndef isnan
#define isnan(a) (a != a)
#endif
考虑到(!X = X)并不总是保证的NaN(例如,如果使用-ffast-运算功能),我已经使用:
#define IS_NAN(x) (((x) < 0) == ((x) >= 0))
号码不能同时<0和> = 0,所以如果真数比以下,也不大于或等于零既不此检查只传递。这基本上是没有数字在所有,或NaN。
您也可以使用这个,如果你喜欢:
#define IS_NAN(x) (!((x)<0) && !((x)>=0)
我不知道这是如何-ffast,数学虽然受到影响,所以你的里程可能会有所不同。
此工作的:
#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
在我看来,最好的真正的跨平台的方法是使用一个工会,并测试双位模式来检查的NaN。
我还没有彻底测试此解决方案,并有可能成为这些位模式工作的更有效的方式,但我认为它应该工作。
#include <stdint.h>
#include <stdio.h>
union NaN
{
uint64_t bits;
double num;
};
int main()
{
//Test if a double is NaN
double d = 0.0 / 0.0;
union NaN n;
n.num = d;
if((n.bits | 0x800FFFFFFFFFFFFF) == 0xFFFFFFFFFFFFFFFF)
{
printf("NaN: %f", d);
}
return 0;
}
在IEEE标准说
当指数是所有1
s
和
尾数不为零,
的数量为一个NaN
。
双是1
符号位,11
指数位和52
尾数位。
做一点检查。
在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
和isfinite
负载2 double/float
常数的.data
版本它们能引起2个数据高速缓存未命中。上述版本不加载任何数据,inf_double_shl1
和inf_float_shl1
常数得到编码为立即操作数到组装说明。
更快isnan2
仅有2组装说明:
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;
}
使用该 ucomisd
指令设置奇偶标志如果任何参数为NaN这一事实。这是std::isnan
没有指定-ffast-math
选项时,是如何工作的。
这通过检查它检测在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;
如以上状态的评价!=一个不会在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格式如果变量是不是有效的整数/浮点型。因此,该代码被检查的字符串的第一个字符是“N”(如在“男”)