2013-07-12 2 views
10

-ffast-math 효과적으로 NaN-/+inf 비활성화 gcc 옵션 때문에 사용하는 것을 선호, 내 성능이 중요한 수학 코드 NaN를 나타내는 아마 다음 가장 좋은 방법을 찾고 있어요. 이상적으로는 (add, mul, div, sub 등 ..)에서 조작하면 센티넬 값은 NaN과 같이 센티널 값을 산출 할 수 있지만, 이것을 달성 할 수있는 유일한 값은 NaN입니다. -0.0NaN를 사용할 수있는 방법 또는 다른 "특별한 두 배"동안이 .. 좋은 센티넬 값은 경우 -ffast - 수학

은 아마도 내 질문에 오히려해야한다, 그것은 등, 또한 -ffast-math에서 비활성화되어 및 (x+0.0) 같은 특정 최적화를 방지 할 수 있기 때문에 적합하지 않을 수도 있습니다 깨지지 않고 많은 수학 최적화를 가능하게 할 수 있습니까?

시스템은 Linux/x64, gcc 4.8.1입니다.

+4

이 스레드가 도움이 될 수 있습니다. [Mingw32 std :: isnan with -ffast-math] (http://stackoverflow.com/questions/7263404/mingw32-stdisnan-with-ffast-math) –

+0

@ShafikYaghmour 감사합니다. 도움이됩니다. – stgtscc

+2

'-fno-finite-math-only -ftrapping-math' 옵션을 사용할 수도 있습니다. http://lua-users.org/lists/lua-l/2009-04/msg00091.html –

답변

4

산술 연산에 의해 전파 될 값을 찾고있는 경우 -ffast-math과 함께 NaN을 계속 사용할 수 있습니다. 문제는 다른 곳에서 발생합니다. -ffast-math을 사용하면 최적화로 인해 일부 연산을 계산에서 제거 할 수 있으며 따라서 NaN 또는 다른 값이 전파 될 수 있음을 보장 할 방법이 없습니다.

예를 들어, 다음, -ffast-math 세트, n0.0를 작성 하드의 원인이되고 그것으로부터 보호 할 수 n에 대한 특수 값은 없습니다. 당신이 할 수있는

float n = NAN; 
n *= 0.0; 

한 가지, Shafik Yaghmour 말했듯이 -ffast-math-fno-finite-math-only -ftrapping-math을 사용하는 것입니다. 그리고 다른 하나는, 나쁜 가치를 기대하는 곳이 몇 군데 밖에 없다면, 그 지점에 정확하게 시험을 치는 것으로 스스로 확인할 수 있습니다.

내가 정말로 생각할 수있는 마지막 옵션 - 실제로 최적화가 절실히 필요한 경우 - 수동으로 NaN (및 아마도 inf) 값을 주입하고 이것이 전파되는 시간을 확인하는 것입니다. 그런 다음 전파 전파가 중지되는 곳에서 NaN (inf)을 테스트합니다. - 이것은 안전하지 않은 방법입니다. 왜냐하면 나는 백분율이 아니기 때문에 -ffast-math은 조건부 동작 흐름을 포함 할 수 있습니다. 가능한 경우 상당한 기회가 있습니다.이 솔루션은 유효하지 않습니다. 따라서 위험하고 선택하면 계산의 모든 가지를 다루는 매우 무거운 테스트가 필요합니다.

일반적으로 나는 오히려 마지막 해결책에 반대 할 것이지만, 실제로는 기회가 있습니다. NaN (inf) 값은 전체 계산 또는 거의 전체적으로 전파되므로 값을 구할 수 있습니다. 따라서 위험을 감수하고 싶을 수 있습니다.


inf 점검하는 것 Shafik Yaghmour 말했듯이

inline int isnan(float f) 
{ 
    union { float f; uint32_t x; } u = { f }; 
    return (u.x << 1) > 0xff000000u; 
} 

와 함께, 당신이 할 수있는 -ffast-mathNaN에 대한 확인 및

inline int isnan(double d) 
{ 
    union { double d; uint64_t x; } u = { d }; 
    return (u.x << 1) > 0xff70000000000000ull; 
} 

에 대한 double

inline int isinf(float f) 
{ 
    union { float f; uint32_t x; } u = { f }; 
    return (u.x << 1) == 0xff000000u; 
} 

inline int isinf(double d) 
{ 
    union { double d; uint64_t x; } u = { d }; 
    return (u.x << 1) == 0xff70000000000000ull; 
} 
,

isnanisinf을 병합 할 수도 있습니다.