2014-01-28 3 views
2

다음과 같은 코드가 있는데 아주 이상한 행동을합니다. 누구나 왜 그런지 알 수 있나요?C++ 함수 결과 비교

#include <iostream> 

long global = 20001; 

double foo() {return global/1000.0;} 

int main(int,char**) { 
    if (foo() == foo()) { 
    std::cout << "true\n"; 
    } else { 
    std::cout << "false\n"; 
    } 

    return 0; 
} 

매번 동일한 결과를 반환하지만 대신 false를 인쇄하므로이 값이 true로 인쇄됩니다.

내가 OS의 문제는,하지만 가능성이 다른 OS

+0

시험해보기 : flost epsilon = 0.001f; if (foo() - foo() <엡실론) .... – AdamF

+1

코드를 컴파일하고 'true'응답을 받았습니다. 나는 gcc 4.6.3과 함께 우분투 12.04를 사용하고있다. OS가 중요 할 수있는 것처럼 보입니다. – Kevin

+0

g가있는 Fedora에서 'true'를 얻었습니다. – Octopus

답변

3

OS는 아마 문제가되지 않지만, 컴파일러와 아키텍처는 않습니다. 인텔에서는 일반적으로 을 부동 소수점 레지스터에 반환하는 것이 일반적이며, 부동 소수점 레지스터에는 의 64 비트 정밀도 (double 값이 아닌 53)가있는 부동 소수점 값이 반환됩니다. 물론, 컴파일러는 해당 레지스터에 직접 산술 연산을 수행하므로 결과적으로 64 비트 정밀도의 값이 반환됩니다.

물론 컴파일러가 함수를 호출하는 코드를 생성 할 때 함수는 해당 레지스터를 사용할 수 있기 때문에 은 값을 레지스터에 남겨 둘 수 없습니다. 그래서 그것은 그것을 기억에 넘칩니다. double로 56 비트. == 연산자는 첫 번째 호출의이 56 비트 값을 두 번째 호출의 64 비트 값과 비교하고 이 같지 않음을 확인합니다.

컴파일러가 함수를 인라인하면 문제가 사라질 수 있다고 덧붙일 수 있습니다.

표준에 따라 모두 합법적입니다.

+0

매우 합리적인데, 변수를 로컬에 저장하지 않고도 비교 작업을 수행 할 수있는 방법이 있습니까? 이 코드는 훨씬 더 큰 함수에서 가져온 것입니다. 로컬에있는 값을 저장하는 것은 실제로 옵션이 아닙니다. –

+1

-ffloat-store는 부동 소수점 비교가 레지스터에서 일어나지 않도록하여이를 수정하는 것으로 보입니다. 고마워, 너는 천재 야. –

1

복식은 평가하지 문제에 그것을 시도 할 기회가 없었어요 모르겠어요 솔라리스 10에 ++ g을 사용하여 구축 항상 정확히 동일한 값으로 설정됩니다 (본질적으로 반올림 오류).

정수를 반환하기 위해 함수를 변경하려면 예상되는 동작을 수행했을 수 있습니다. 이 질문에 매우 유사

: Deals with comparing floats

이 시도 :

#include <iostream> 
#include <limits> 

long global = 20001; 
double epsilon = std::numeric_limits::epsilon<double>(); 

double foo() {return global/1000.0;} 

int main(int,char**) { 
    if (foo() - foo() > epsilon) { 
    std::cout << "true\n"; 
    } else { 
    std::cout << "false\n"; 
    } 

    return 0; 
} 
+0

_do_를 두 배로 늘리면 항상 동일한 값으로 평가됩니다. 이 문제는 레지스터에서 Intel의 확장 된 정밀도의 부작용입니다. –

+0

아. 나는 그것을 몰랐다. 그래서 그것은 인텔의 유일한 문제입니까? – Jmc

+1

오늘은 아마도. 과거에는 모토로라 칩이 확장 된 정밀도를 사용하여 동일한 문제를 나타낼 수 있다고 생각합니다. –