를 확인하는 경우 이중(또는 부동)은 할머니에서는 C++
문제
이 있 isnan()함수는?
PS.:나 MinGW (경우에는 차이가).
나는 이를 사용하여 해결 isnan()서 <math.h>
, 는 존재하지 않에 <cmath>
, 가 #include
ing 습니다.
해결책
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++(을 통해 포함 cmath
나 math.h
),무엇을 일으킬 수 있습니다 더 혼란과 개발자들 수 있다고 가정하는 표준다.
에 대한 참고 Viusal C++,위에서 언급한 바와 같이,그것을 제공하지 않습 std::isnan
도 std::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 표준은 지수가 전부 일 때를 말합니다 1
S와 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"에서와 같이)