2010-12-20 5 views
4

내 C 코드가 어떻게 결과를자를 지 예측하는 데 약간의 어려움이 있습니다. 다음을 참조하십시오.캐스팅시 다른 잘림 결과

float fa,fb,fc; 
short ia,ib; 

fa=160 
fb=0.9; 
fc=fa*fb; 
ia=(short)fc; 
ib=(short)(fa*fb); 

결과는 ia = 144, ib = 143입니다.

두 결과에 대한 추론을 이해할 수 있지만 왜 두 계산이 다르게 취급되는지 이해할 수 없습니다. 누구든지이 행동이 정의 된 곳으로 안내하거나 차이점을 설명 할 수 있습니까?

편집 : 결과는 Intel 코어 i3-330m에서 MS Visual C++ Express 2010으로 컴파일됩니다. 동일한 머신에서 Virtual Box 아래에 gcc 4.4.3 버전 (Ubuntu 4.4.3-4ubuntu5)과 동일한 결과가 나타납니다.

+0

어떤 대상 CPU입니까? – EboMike

답변

7

fc과 같은 변수 float에 할당 할 때 사용하는 것보다 컴파일러에서 fa*fb과 같은 하위 표현식에 대해 더 많은 정밀도를 사용할 수 있습니다. 따라서 fc= 부분은 결과를 약간 변경하는 것입니다 (그리고 정수 잘림이 달라지기까지합니다).

+0

그리고 컴파일러가 일반적으로 그렇게합니다. x86 프로세서 인 IIRC는 항상 80 비트 부동 소수점을 처리합니다 ('long double'). –

+1

Windows가 80 비트 지원을 사용하지 못하게하고 모든 것을 64 비트로 강제 실행하는 것을 제외하고, Windows OpenGL 라이브러리가 깨져서 32 비트 정밀도로 모든 작업을 수행하는 fpu 모드를 변경하면 ... –

3

aschepler 잘 무슨 일이 일어나고 있는지의 메커니즘을 설명하지만, 코드와 함께 근본적인 문제는 불안정한 방식으로의 근사치의 값에 따라 코드에서 float으로 존재하지 않는 값을 사용하고 있습니다. 부동 소수점 값 0.9 또는 0.9f이 아닌 0.9 (실제 숫자 0.9 = 9/10)을 9로 곱한 다음 10으로 나누거나 부동 소수점 유형을 잊어 버리고 10 진수 산술 라이브러리를 사용해야합니다.

불안정한 점들이 여기 예제 에서처럼 고립되어있을 때 문제 주변을 싸고 더러운 방법은 오차보다 크지 만 그 차이보다 작은 값 (일반적으로 0.5)을 추가하는 것입니다. 절단 전의 다음의 정수

0

이것은 컴파일러에 따라 다릅니다. 광산 (gcc 4.4.3)에서는 동일한 표현식이 최적화되어 있기 때문에 두 표현식 모두에 대해 동일한 결과, 즉 -144를 생성합니다.

다른 사람이 무슨 일이 일어 났는지 잘 설명했습니다. 즉, 컴파일러가 내부적으로 곱셈을 수행하기 전에 부동 소수점을 80 비트 FPGA 레지스터로 승격시킨 다음 다시 부동 또는 짧게 변환하기 때문에 차이가 발생할 가능성이 높습니다.

ib = (short)(float)(fa * fb);을 쓰는 경우 내 가설이 참이면 fc를 짧게 변환 할 때와 동일한 결과를 얻어야합니다.

+0

MS Visual C++ 표하다. 하지만 동일한 머신 (코어 i3 - 330m)에있는 버추얼 박스에서 gcc 4.4.3 버전 (Ubuntu 4.4.3-4ubuntu5)과 동일한 결과를 얻었습니다. – tkw954