ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [컴시설] 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-precision

     t1 = 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 마다 컴파일러 마다 값이 다를 수 있다는 글들을 읽었다. 앞으로 디버깅을 하면서 어려움에 닥칠 수 있는 중요한 요인을 알 수 있었다.

Designed by Tistory.