문제

이 있 isnan()함수는?

PS.:나 MinGW (경우에는 차이가).

나는 이를 사용하여 해결 isnan()서 <math.h>, 는 존재하지 않에 <cmath>, 가 #includeing 습니다.

도움이 되었습니까?

해결책

IEEE 표준에 따르면, NAN 값은 그들과 관련된 비교가 언제나 거짓. 즉, 플로트 F의 경우 f != f 사실이 될 것입니다 f가 nan이면.

아래의 일부 의견이 지적했듯이 모든 컴파일러가 코드를 최적화 할 때이를 존중하는 것은 아닙니다.

IEEE 플로팅 포인트를 사용한다고 주장하는 모든 컴파일러의 경우이 트릭 ~해야 한다 일하다. 그러나 나는 그것을 보장 할 수 없습니다 ~ 할 것이다 실제로 일하십시오. 의심스러운 경우 컴파일러를 확인하십시오.

다른 팁

이 없 isnan() 함수에서 사용할 수 있는 현재 C++표준 라이브러리입니다.에서 소개되었습니다 C99 고로 정의 매크로 하지 않는 기능입니다.요소의 표준 라이브러리에 의해 정의된 C99 하지 않은 부분의 현 C++표준은 ISO/IEC14882:1998 도 update ISO/IEC14882:2003.

2005 년에 의 기술 보고서 1 제안되었다.이 TR1 제공합과의 호환성 C99C++.사실에도 불구하고 그것은 적이있는 공식적으로 채택되 C++표준,많은 것(GCC4.0+Visual C++9.0+ C++구현을 제공 할 TR1 기능,그들 모두 또는 일부만(Visual C++9.0 을 제공하지 않습 C99 수학능).

는 경우 TR1 사용할 수 있음 cmath 을 포함 C99 요소 isnan(), isfinite(), 니다,등등.그러나 그들은 정의된 기능으로지,매크로,일반적으로 std::tr1:: 네임스페이스,하지만 많은 구현(i.eGCC4+리눅스에서 또는 XCode 에서 Mac OS X10.5+)그들에게 주입에 직접 std::, 래 std::isnan 은 제대로 정의되어 있습니다.

또한,일부 구현 C++여전히 C99 isnan() 매크로를 사용할 수 있는 C++(을 통해 포함 cmathmath.h),무엇을 일으킬 수 있습니다 더 혼란과 개발자들 수 있다고 가정하는 표준다.

에 대한 참고 Viusal C++,위에서 언급한 바와 같이,그것을 제공하지 않습 std::isnanstd::tr1::isnan, 하지만 그것이 제공하는 확장 기능으로 정의 _isnan() 은 부터 사용 가능 Visual C++6.0

에 XCode,더 많은 재미 있습니다.으로 언급하고,GCC4+정의 std::isnan.이전 버전에 대한의 컴파일러 및 라이브러리 형태로 엑스 코드,그것은 보인다(기 관련 토론),기회가 없었어요 자신을 확인)두 기능은 정의 __inline_isnand() 에서 인텔과 __isnand() 에 전원 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/math/isnan

G ++를 사용하는 경우 -fast -math와 호환되지 않습니다. 다른 제안은 아래를 참조하십시오.


기타 솔루션 : 비 C ++ 11 호환 도구를 사용하는 경우

C99의 경우 C에서 이것은 매크로로 구현됩니다. isnan(c)int 값을 반환합니다. 유형 x 플로트, 이중 또는 긴 더블이어야합니다.

다양한 공급 업체가 기능을 포함하거나 포함하지 않을 수도 있습니다. isnan().

아마도 휴대용을 확인하는 방법 NaN IEEE 754 속성을 사용하는 것입니다 NaN 그 자체와 같지 않습니다 : 즉 x == x 거짓입니다 x 존재 NaN.

그러나 마지막 옵션은 모든 컴파일러 및 일부 설정 (특히 최적화 설정)에서 작동하지 않을 수 있으므로 최후의 수단에서는 항상 비트 패턴을 확인할 수 있습니다 ...

또 한있다 헤더 전용 라이브러리 부동 소수

#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 함수 템플릿, 또는 시각적 C ++ _isnan 기능.

불행히도 사용해야 할 사람들을 감지하는 것은 다소 비현실적입니다.

불행히도, NANS와 IEEE 754 표현이 있는지 여부를 감지 할 수있는 신뢰할 수있는 방법은 없습니다. 표준 라이브러리는 공식적인 방식을 제공합니다 (numeric_limits<double>::is_iec559). 그러나 실제로 G ++와 같은 컴파일러는이를 나선 것입니다.

이론적으로는 간단하게 사용할 수 있습니다 x != x, 그러나 G ++ 및 Visual C ++와 같은 컴파일러는이를 사용합니다.

결국, 특정 사항을 테스트하십시오 Nan Bitpatterns, 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> _

컴파일러가 C99 확장을 지원하면 std :: isnan이 있지만 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 방지

이 질문에 대한 나의 대답은입니다 소급 수표를 사용하지 마십시오 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 ) 진실을 반환하고 심지어 (-inf < inf) 진실을 반환합니다. 그래서 내 경험상 코드의 동작은 자주 여전히 원하는대로).

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 (모든 지수 비트 세트, 하나 이상의 분수 비트 세트)의 정의를 사용하고 (int) = sizeof (float) = 4를 가정합니다. Wikipedia에서 NAN을 찾을 수 있습니다.

bool IsNan( float value ) { return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000; }

C ++ 14 기준으로 부동 소수점 번호가 있는지 테스트하는 방법에는 여러 가지가 있습니다. value Nan입니다.

이 방법 중에서 비트 확인 숫자의 표현 중에서, 나의 원래 대답에 언급 된 바와 같이, 안정적으로 작동합니다. 특히, std::isnan 그리고 종종 제안 된 수표 v != v, 누군가가 부동 소수점 최적화가 필요하다고 결정했을 때 코드가 올바르게 작동하지 않도록 안정적으로 작동하지 않고 사용해서는 안됩니다. 이러한 상황이 변경 될 수 있고 컴파일러는 더 많이 준수 할 수 있지만, 원래 답변 이후 6 년 동안 발생하지 않은이 문제의 경우.

약 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과 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-Detector로 작동하지 않는다는 것입니다. 여기서는 매우 실질적인 관심사입니다).

[C:\my\forums\so\282  (detect NaN)]
> g ++ -전환 | "++"찾기
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 /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을 테스트 할 수있는 또 다른 것을 알게되었습니다. 또 다른 대답 여기, 즉 ((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) );
}

나에게는 솔루션이 매크로가 될 수 있으며,이를 명시 적으로 인라인으로 충분히 빠르게 만들 수 있습니다. 또한 플로트 유형에도 작동합니다. 값 자체가 아닌 유일한 경우는 값이 숫자가 아닌 경우입니다.

#ifndef isnan
  #define isnan(a) (a != a)
#endif

(x! = x)가 NAN에 항상 보장되는 것은 아니라는 점을 고려할 때 (-ffast -math 옵션을 사용하는 경우)를 사용하고 있습니다.

#define IS_NAN(x) (((x) < 0) == ((x) >= 0))

숫자는 <0과> = 0이 될 수 없으므로 실제로이 점검은 숫자가 0보다 작거나 0보다 크지 않은 경우에만 전달됩니다. 기본적으로 전혀 숫자가 없습니다.

원하는 경우 다음을 사용할 수 있습니다.

#define IS_NAN(x) (!((x)<0) && !((x)>=0)

그래도 이것이 -ffast -math의 영향을받는 방법을 잘 모르겠으므로 마일리지가 다를 수 있습니다.

이것은 작동합니다 :

#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

진정으로 진정으로 교차 플랫폼 접근 방식은 노조를 사용하고 이중의 비트 패턴을 테스트하여 NANS를 확인하는 것 같습니다.

이 솔루션을 철저히 테스트하지 않았으며 비트 패턴으로 작업하는보다 효율적인 방법이있을 수 있지만 작동해야한다고 생각합니다.

#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와 Mantissa는 0이 아니며 숫자는 NaN. 이중 IS 1 사인 비트, 11 지수 비트 및 52 만티사 비트. 약간 확인하십시오.

x86-64에서는 NAN 및 Infinity를 확인하는 매우 빠른 방법을 가질 수 있습니다. -ffast-math 컴파일러 옵션. (f != f, std::isnan, std::isinf 항상 양보합니다 false ~와 함께 -ffast-math).


최대 지수를 확인하면 NAN, Infinity 및 유한 번호 테스트를 쉽게 수행 할 수 있습니다. 무한대는 0 만티사가있는 최대 지수이며, NAN은 최대 지수 및 0이 아닌 Mantissa입니다. 지수는 최상위 부호 비트 후 다음 비트에 저장되므로 간판 비트를 제거하고 지수를 최상위 비트, 마스킹 없음 (마스킹없이 지수를 최상위 비트로 만들 수 있습니다).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 인 경우 Parity 플래그를 설정합니다. 이것이 방법입니다 std::isnan 아니요 -ffast-math 옵션이 지정됩니다.

이것은 Infinity와 NAN을 검출하여 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;

위의 의견으로 상태 a! = a는 G ++ 및 일부 컴파일러에서 작동하지 않지만이 트릭은해야합니다. 효율적이지는 않지만 여전히 방법입니다.

bool IsNan(float a)
{
    char s[4];
    sprintf(s, "%.3f", a);
    if (s[0]=='n') return true;
    else return false;
}

기본적으로 G ++에서 (다른 사람에 대해서는 잘 모르겠지만) Printf Prints 'nan' 'on %d 또는 %.f 형식이 유효한 정수/플로트가 아닌 경우. 따라서이 코드는 String의 첫 번째 문자가 'n'이지는 것을 확인합니다 ( "nan"에서와 같이)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top