오류가있는 경우 nan 또는 inf를 반환 할 수있는 숫자 메서드가 있으며, 테스트 목적으로 상황이 올바르게 처리되고 있는지 확인하기 위해 일시적으로 nan 또는 inf를 반환하도록 강제하고 싶습니다. C에서 nan 및 inf 값을 생성 하는 신뢰할 수 있고 컴파일러 독립적 인 방법이 있습니까?
약 10 분 동안 인터넷 검색을 한 후 컴파일러 종속 솔루션 만 찾을 수있었습니다.
오류가있는 경우 nan 또는 inf를 반환 할 수있는 숫자 메서드가 있으며, 테스트 목적으로 상황이 올바르게 처리되고 있는지 확인하기 위해 일시적으로 nan 또는 inf를 반환하도록 강제하고 싶습니다. C에서 nan 및 inf 값을 생성 하는 신뢰할 수 있고 컴파일러 독립적 인 방법이 있습니까?
약 10 분 동안 인터넷 검색을 한 후 컴파일러 종속 솔루션 만 찾을 수있었습니다.
답변:
구현에 다음이 있는지 테스트 할 수 있습니다.
#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif
의 존재는 INFINITYC99 (또는 적어도 최신 초안)에 의해 보장되며 "사용 가능한 경우 양수 또는 부호없는 무한대를 나타내는 float 유형의 상수 표현식으로 확장됩니다. 그렇지 않으면 번역시 오버플로되는 float 유형의 양의 상수로 확장됩니다."
NAN 정의되거나 정의되지 않을 수 있으며 "구현이 float 유형에 대해 조용한 NaN을 지원하는 경우에만 정의됩니다. 이는 조용한 NaN을 나타내는 float 유형의 상수 표현식으로 확장됩니다."
부동 소수점 값을 비교하는 경우 다음을 수행하십시오.
a = NAN;
그렇다하더라도,
a == NAN;
거짓입니다. NaN을 확인하는 한 가지 방법은 다음과 같습니다.
#include <math.h>
if (isnan(a)) { ... }
다음 a != a을 수행 할 수도 있습니다 a. NaN 인지 테스트합니다 .
도있다 isfinite(), isinf(), isnormal(), 및 signbit()매크로에 math.hC99한다.
C99에는 다음과 같은 nan기능 도 있습니다 .
#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);
(참조 : n1256).
a != a해서는 안됩니다 .
a숫자 가 아닌 경우 a == NANfalse를 반환 하도록 요구하지 않습니다 . IEEE에서 필요합니다. IEEE를 준수하는 구현도 대부분 그렇게 합니다 . 때 isnan()구현되지 여전히 더 나은 직접 코드보다 테스트를 마무리합니다 a == NAN.
C (또는 C ++) 표준이 부동 소수점 수학 유형이 NAN 또는 INF를 지원해야한다고 말하지 않기 때문에이를 수행하는 컴파일러 독립적 인 방법은 없습니다.
편집 : 방금 C ++ 표준의 문구를 확인한 결과 다음 함수 (템플릿 클래스 numeric_limits의 구성원)가 다음과 같이 표시됩니다.
quiet_NaN()
signalling_NaN()
"사용 가능한 경우"NAN 표현을 반환합니다. "가능한 경우"가 의미하는 바를 확장하지 않고 "구현의 FP 담당자가 지원하는 경우"와 같은 것으로 추정됩니다. 마찬가지로 기능이 있습니다.
infinity()
"사용 가능한 경우"양의 INF 담당자를 반환합니다.
이것들은 모두 <limits>헤더에 정의되어 있습니다. C 표준에도 비슷한 것이 있다고 생각하지만 (아마도 "사용 가능한 경우") 현재 C99 표준의 사본이 없습니다.
<math.h>정의 nan(), nanf()및 nanl()의 NaN 돌려 다른 표현 (a로서 double, float그리고 int각각)과 무한대 (사용 가능한 경우)를 하나 생성하여 리턴 될 수도 log(0)또는 무언가. C99에서도이를 확인하는 표준 방법은 없습니다. <float.h>헤더 ( <limits.h>정수형입니다)에 대한 불행하게도 침묵 inf하고 nan값.
nanl()반환합니다 . 나는 그것을 타이핑 할 때 그것을 깨닫지 못한 이유를 모른다. long doubleint
이것은 float및 double:
double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;
편집 : 누군가 이미 말했듯이 이전 IEEE 표준은 이러한 값이 함정을 유발해야한다고 말했습니다. 그러나 새 컴파일러는 트랩이 오류 처리를 방해하기 때문에 거의 항상 트랩을 끄고 주어진 값을 반환합니다.
#define is_nan(x) ((x) != (x))NAN에 대한 간단하고 이식 가능한 테스트로 유용 할 수 있습니다.
컴파일러 독립적 인 방법이지만 프로세서 독립적 인 방법은 아닙니다.
int inf = 0x7F800000;
return *(float*)&inf;
int nan = 0x7F800001;
return *(float*)&nan;
이것은 IEEE 754 부동 소수점 형식을 사용하는 모든 프로세서에서 작동합니다 (x86이 수행함).
업데이트 : 테스트 및 업데이트되었습니다.
(float &)하시겠습니까? 그것은 나에게 C처럼 보이지 않습니다. 당신은 필요합니다int i = 0x7F800000; return *(float *)&i;
0x7f800001A가 이른바 신호 는 IEEE-754 표준에 NaN이 있습니다. 대부분의 라이브러리와 하드웨어는 신호 NaN을 지원하지 않지만 .NET과 같은 조용한 NaN을 반환하는 것이 좋습니다 0x7fc00000.
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);
strtodNaN과 Inf를 필요로 하며 변환 합니다 .
<inf.h>
/* IEEE positive infinity. */
#if __GNUC_PREREQ(3,3)
# define INFINITY (__builtin_inff())
#else
# define INFINITY HUGE_VALF
#endif
과
<bits/nan.h>
#ifndef _MATH_H
# error "Never use <bits/nan.h> directly; include <math.h> instead."
#endif
/* IEEE Not A Number. */
#if __GNUC_PREREQ(3,3)
# define NAN (__builtin_nanf (""))
#elif defined __GNUC__
# define NAN \
(__extension__ \
((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; }) \
{ __l: 0x7fc00000UL }).__d)
#else
# include <endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
# define __nan_bytes { 0x7f, 0xc0, 0, 0 }
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define __nan_bytes { 0, 0, 0xc0, 0x7f }
# endif
static union { unsigned char __c[4]; float __d; } __nan_union
__attribute_used__ = { __nan_bytes };
# define NAN (__nan_union.__d)
#endif /* GCC. */
나는 보통 사용
#define INFINITY (1e999)
또는
const double INFINITY = 1e999
표현 가능한 가장 높은 double 값이 대략이므로 적어도 IEEE 754 컨텍스트에서 작동합니다 1e308. 1e309마찬가지로 잘 작동 1e99999하지만 3 개의 9는 충분하고 기억에 남습니다. 이것은 이중 리터럴 (이 #define경우) 또는 실제 Inf값이므로 128 비트 ( "long double") 부동 소수점을 사용하더라도 무한대로 유지됩니다.
1e999리터럴이 더 이상 +Infinity. 머피의 법칙에 따르면 이것은 알고리즘을 깨뜨립니다. 더 나쁜 것은 "128 비트"빌드를하는 인간 프로그래머가 그 오류를 미리 발견하지 못할 것입니다. 즉 ,이 오류가 발견되고 인식되면 너무 늦을 가능성이 큽니다 . 매우 위험한.