2017-02-03 2 views
3

일부 코드를 32 비트에서 64 비트로 이식하고 있으며 응답이 동일하도록 보장합니다. 그렇게하면서, 나는 atan2f가 둘 사이에서 다른 결과를 주었다는 것을 알아 차렸다.atan2f는 m32 플래그로 다른 결과를 제공합니다.

gcc compilerTest.c -o 64bit.out -lm 
: 빌드 할 때

atan2f: 1.914544820785522 
atan2: 1.914544820785522 

:

gcc compilerTest.c -m32 -o 32bit.out -lm 

이 제공 :로 구축 할 때

#include <stdio.h> 
#include <math.h> 

void testAtan2fIssue(float A, float B) 
{ 
    float atan2fResult = atan2f(A, B); 
    printf("atan2f: %.15f\n", atan2fResult); 

    float atan2Result = atan2(A, B); 
    printf("atan2: %.15f\n", atan2Result); 
} 

int main() 
{ 
    float A = 16.323556900024414; 
    float B = -5.843180656433105; 
    testAtan2fIssue(A, B); 
} 

:

나는이 분 생식을 만들어

이 제공 :

atan2f: 1.914544701576233 
atan2: 1.914544820785522 

참고는 ATAN2는 두 경우 모두 같은 결과를 제공하지만, atan2f하지 않습니다.

것들 내가 시도 :

  1. SSE -msse2 -mfpmath =와 32 비트 버전을 구축 -ffloat 매장

  2. 와 32 비트 버전을 구축 -mfpmath = 387을 사용하여 64 비트 버전 빌드

아무 것도 결과를 변경하지 않았습니다.

가 (이 모든이가 부동 소수점 연산 32 비트 64 대 비트 아키텍처에서 발생하는 방식으로 할 수있는 뭔가가 가설 기반으로했다.)

질문 :

무엇입니까 내 그 (것)들을 얻기를위한 선택권은 동일한 결과를 주는가? (사용할 수있는 컴파일러 플래그가 있습니까?) 또한 여기에서 무슨 일이 일어나고 있습니까?

저는 도움이된다면 i7 컴퓨터에서 실행 중입니다.

+0

atan2f로 테스트 : % .15f \ n "'_ 충분하지 않을 수도 있습니다. 조사를 위해서''% .16e \ n "'또는 더 나은''% a \ n"'을 사용하십시오. – chux

+0

왜 두 개의 서로 다른 라이브러리가 정확히 같은 결과를 제공하고 어떤 크기가 두 플랫폼에서 모두 'float'이 될 것으로 예상합니까? 차이점은 걱정하지 않을 것입니다. – Olaf

+0

'1.914544701576233'과'1.914544820785522 '는 [ULP] (https://en.wikipedia.org/wiki/Unit_in_the_last_place)의 2 비트와 다릅니다. – chux

답변

0

16 진수 표기로보기가 더 쉽습니다.

여기에 무슨 일이 일어나고 있는지
void testAtan2fIssue(float A, float B) { 
    double d = atan2(A, B); 
    printf("  atan2 : %.13a %.15f\n", d, d); 
    float f = atan2f(A, B); 
    printf("  atan2f: %.13a %.15f\n", f, f); 
    printf("(float) atan2 : %.13a %.15f\n", (float) d, (float) d); 

    float f2 = nextafterf(f, 0); 
    printf("problem value : %.13a %.15f\n", f2, f2); 
} 

// _ added for clarity 
     atan2 : 0x1.ea1f9_b9d85de4p+0 1.914544_797857041 
     atan2f: 0x1.ea1f9_c0000000p+0 1.914544_820785522 
(float) atan2 : 0x1.ea1f9_c0000000p+0 1.914544_820785522 
problem value : 0x1.ea1f9_a0000000p+0 1.914544_701576233 

?

floatdouble에서 변환은 최적 것으로 예상 할 수있다, 그러나 아크 탄젠트 기능은 다양한 플랫폼에 떨어져 몇 ULP 수 있습니다. 1.914544701576233은 그 다음으로 작으며 float 값이며 약간 더 낮은 역 탄젠트 계산을 반영합니다.


같은 결과를 제공하도록하는 방법을 내 옵션은 무엇입니까?

몇. 코드는 코드베이스에서 자신의 my_atan2()을 굴릴 수 있습니다. 그럼에도 미묘한 구현 차이가있을 수 있습니다. @stark

대신 분 변화에 대해 코드 검사를 허용하는 것이 좋습니다.

+0

나는이 질문을 (m32 이외의) 동일하게 만들 수있는 질문을하고 있다고 생각한다. – TinyTheBrontosaurus

+0

고마워. 불행하게도 저는 레거시 코드 기반으로 작업하고 있습니다. 따라서 미세한 변화에 견딜 수 있도록 만드는 것이 중요하지 않습니다. 아아, 내가이 문제를 해결해야 할 것 같아. – powerss

+0

@TinyTheBrontosaurus 사실,이 문제를 해결하기 위해 _flag_를 사용하는 것이 하나의 방법 일 수 있습니다. 그러나 나는 간단한 gcc 옵션 변경으로 제한된 게시물을 보지 못했지만 더 개방적입니다. – chux

관련 문제