-
[컴시설] IA32 :: FPU와 Memory의 정밀도 차이, 컴파일러마다 다른 rounding정책정리필요2 2007. 9. 22. 20:15
나는 이 간단한 소스코드가 무엇을 의미하는지 알아야한다.
#include <stdio.h>double recip(int denom)
{
return 1.0/(double) denom;
}void do_nothing() {}
void test1(int denom)
{
double r1, r2;
int t1, t2;r1 = recip(denom); //double-precision
r2 = recip(denom); //extended-precisiont1 = r1 == r2;
do_nothing();
t2 = r1 == r2;
printf("test1 t1: r1 %f %c = r2 %f\n", r1, t1 ? '=' : '!', r2);
printf("test1 t2: r1 %f %c = r2 %f\n", r1, t2 ? '=' : '!', r2);
}
main(void){
int denom = 10;test1(denom);
}
실행하면 다음과 같이 나온다.
책에는 아래와 같이 하나는 다르다고 나와야 되는데 왜이러는거야~~~
끼아아~~악~
test1 t1: r1 0.100000 != r2 0.100000
test1 t2: r1 0.100000 == r2 0.100000
책에서는 gcc3.14 를 사용했다고 한다.
알고있듯이 컴퓨터는 2진수를 사용하기 때문에 0.1등의 값을 정확하게 표현하지 못한다. 그래서 소수점 이하의 값은 정밀도에 따라서 달라진다.
IA32에서는 부동소수점 연산에서 FPU 는 확장정밀도를 쓰고 Memory는 배정밀도를 쓰는 서로 다른 정밀도를 이기 때문에 같은 값을 각각 floating point register 와 memory 에 두고 비교연산을 하면 소수점 이하가 달라지기 때문에 다르게 나오는 것이다.
책의 예제를 실행시켰을 때 책의 결과와 다르게 나온 이유는 최신의 컴파일러들은 비교연산과 부동소수점연산의 정밀도를 정당히 trade off 하여 비교연산시 정확도를 위해 부동소수점을 보정해주는 기능을 가지고 있다.
책에서 쓰고 있는 gcc3.14의 경우 결과가
test1 t1: r1 0.100000 != r2 0.100000
test1 t2: r1 0.100000 == r2 0.100000
위와 같이 나온것은 rounding정책이 부동소수점의 정밀도에 비중을 두고 비교연산시 floating point register 와 memory에 저장된 서로 다른 정밀도의 두 수를 보정해 주지 않고 그대로 비교하기 때문에 다르게 나오는 것이다.
IA32의 FPU가 80bit 확장정밀도를 사용하고 memory는 64bit 배정밀도를 사용하여 같은 값을 각각 저장하고 비교하면 다를 수 있는 값이 컴파일러에 의해 보정된다는 사실을 알았다. 이러한 정밀도 정책들이 processor 마다 OS 마다 컴파일러 마다 값이 다를 수 있다는 글들을 읽었다. 앞으로 디버깅을 하면서 어려움에 닥칠 수 있는 중요한 요인을 알 수 있었다.