有 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是NaNfalse否则

<强>参考

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将是xNaN

但是最后的选项可能无法与每一个编译器和一些设置(特别优化设置)工作,所以在最后的手段,可以随时查询位模式...

还有一个 仅标头库 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标准说 当指数是所有1s 和 尾数不为零, 的数量为一个NaN。 双是1符号位,11指数位和52尾数位。 做一点检查。

在x86-64的,你可以有检查的NaN和无穷极快的方法,无论哪个工作-ffast-math编译器选项。 (f != fstd::isnanstd::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段,并在最坏的情况下isinfisfinite负载2 double/float常数的.data版本它们能引起2个数据高速缓存未命中。上述版本不加载任何数据,inf_double_shl1inf_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”(如在“男”)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top