문제

오늘 아침에 작은 WTF 순간이있었습니다. wtf는 다음과 같이 요약 할 수 있습니다.

float x = 0.2f;
float y = 0.1f;
float z = x + y;
assert(z == x + y); //This assert is triggered! (Atleast with visual studio 2008)

그 이유는 그 표현이었습니다 x + y 두 배로 홍보되고 절단 된 버전과 비교됩니다. z. (내가 변하면 z 에게 double 인식이 트리거되지 않습니다).

정확한 이유로 결과를 단일 정밀도로 변환하기 전에 모든 부동 소수점 산술을 이중 정밀하게 수행하는 것이 합리적이라는 것을 알 수 있습니다. 나는 표준에서 다음 단락을 발견했습니다 (나는 이미 알고 있었지만이 맥락에서는 그렇지 않은 것 같아요).

4.6.1."유형의 RValue float 유형의 rvalue로 변환 할 수 있습니다 double. 가치는 변하지 않습니다. "

내 질문은입니다 x + y 두 배로 승진하거나 컴파일러의 재량에 따라 보장 되나요?

업데이트: 많은 사람들이 사용해서는 안된다고 주장했기 때문에 == 플로팅 포인트의 경우, 제가 작업하는 특정 경우에 정확한 비교가 정당하다고 진술하고 싶었습니다.

부동 소수점 비교 ~이다 까다 롭습니다. 여기 흥미로운 점이 있습니다 링크 언급되지 않은 주제에 대해.

도움이 되었습니까?

해결책

당신은 일반적으로 그것을 가정 할 수 없습니다 == 부동 소수점 유형에 대해 예상대로 작동합니다. 둥근 값을 비교하거나 같은 구조물을 비교하십시오 abs(a-b) < tolerance 대신에.

프로모션은 전적으로 컴파일러의 재량에 달려 있으며 대상 하드웨어, 최적화 수준 등에 따라 다릅니다).

이 특정 사례에서 일어나고있는 것은 값이 메모리보다 더 높은 정밀도로 FPU 레지스터에 저장된다는 것이 거의 확실합니다. 일반적으로 현대 FPU 하드웨어는 프로그래머가 요청한 내부적으로 정밀도로 두 배 이상의 정밀도로 작동하며 컴파일러가 코드를 생성합니다. 값이 메모리에 저장 될 때 적절한 변환을 만들기 위해; 최적화되지 않은 빌드에서 결과 x+y 비교가 이루어진 시점에 여전히 레지스터에 있지만 z 추억에 저장되어 뒤로 가져와 정밀도를 떠 다니기 위해 잘 렸습니다.

다른 팁

그만큼 다음 표준 C ++ 0x의 작업 초안 섹션 5 지점 11은 말합니다

부유 식 피연산자의 값과 부동 표현의 결과는 유형에 의해 요구되는 것보다 더 큰 정밀도와 범위로 표현 될 수있다. 유형이 변경되지 않습니다

컴파일러의 재량에 따라.

GCC 4.3.2를 사용하면 주장이 있습니다 ~ 아니다 트리거되고 실제로 RValue가 돌아 왔습니다 x + y a float, a보다는 double.

따라서 컴파일러에 달려 있습니다. 그렇기 때문에 두 개의 부동 소수점 값 사이의 정확한 평등에 의존하는 것이 결코 현명하지 않습니다.

C ++ FAQ Lite는 주제에 대한 추가 논의를 가지고 있습니다.

이진 변환에 대한 플로트 번호는 정확한 정밀도를 제공하지 않기 때문에 문제입니다.

그리고 내부 sizeof(float) 바이트는 플로트 번호의 정확한 값을 호소 할 수 없으며 산술 작동은 근사치로 이어질 수 있으므로 평등이 실패합니다.

아래를 참조하십시오

float x = 0.25f; //both fits within 4 bytes with precision
float y = 0.50f;
float z = x + y;
assert(z == x + y); // it would work fine and no assert

나는 그것이 컴파일러의 재량에있을 것이라고 생각하지만, 그것이 당신의 생각이라면 항상 캐스트로 강제로 강요 할 수 있습니까?

플로트를 직접 비교하지 않는 또 다른 이유.

if (fabs(result - expectedResult) < 0.00001)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top