检查C ++中的double(或float)是否为NaN

时间:2009-02-20 18:09:53

标签: c++ double nan

是否有isnan()函数?

PS:我在MinGW(如果这有所不同)。

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

21 个答案:

答案 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 ++(包括cmathmath.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)

第一种解决方案:如果您使用的是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/math/isnan

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


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

对于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.f0.0/0.0nan对于代码的稳定性是一个可怕的克星,必须检测并防止非常小心 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。因此,根据我的经验,代码的行为经常仍然是所希望的)。

在nan

下做什么

您希望在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 != 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; }

stdisinf的{​​{1}}版本从isfinite段中加载2个double/float常量,在最坏的情况下,它们可能导致2次数据高速缓存未命中。以上版本不加载任何数据,.datainf_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”)