cpp에서 precision 변경...

dorado2의 이미지

현재 redhat 7.1, gcc 2.96에서 작업중입니다.

윈도우에선 돌아가는 코드가 리눅스에서 안 돌아가고 있습니다.

이유를 찾아봤더니, 아래와 같은 assert 에러인데...

assert(val>=0.0f);

-0.02 * 50 + 1.00 이 값이 윈도우에선 0으로 나오는데,

(위에서 -0.02 는 1/50의 결과입니다. 이것도 영향이 있을듯)

리눅스에선

-0.00000000000000002082 로 나오네요.

(0이 소숫점 아래 16개..)

precision 문제인 것 같은데, cpp에서 보면 setprecision 같은 함수의 경우는 cout 과 같이 쓰여서 출력시의 자릿수를 고치는 것 같은데, 이건 아닌 거 같고...

위 같은 경우 소숫점 14자리 정도만 정밀도를 보고 비교하도록 고치는 방법이 없을까요?

precision을 소숫점 14자리 정도로 바꾸고 싶은데, 좋은 방법이 없을지...

답변에 미리 감사드립니다.

doldori의 이미지

tolerance를 주면 되지 않을까요?

const double tolerance = 1.e-14;
assert(abs(val) >= tolerance);
ssehoony의 이미지

부동소수의 계산은 모든 cpp 컴파일러가 동일한 로직으로 처리한는게 아니였나요?
예전에 제가 테스트 했을 때는 오차나 결과 등등이 모두
gcc 와 ms 컴파일러가 동일했던 걸로 기억하는데...

lifthrasiir의 이미지

일단 실용적인 방법으로는 doldori 님의 코드처럼 tolerance가 가장 좋은 방법입니다. 실수 값은 믿기가 힘들어서 말이죠 :)

그리고 대충 컴파일 결과를 디스어셈블해서 보니까 리눅스(objdump -d 사용)와 윈도우(-ㅅ-)에서 같은 어셈블리 코드가 나오는 것 같습니다. 하지만 출력 결과는 살짝 다르더군요. 다음은 위에서 말씀하신 -0.02 * 50 + 1.00을 한 단계씩 계산한 결과입니다.

리눅스: (GCC 3.3.5)
-0.0200000000000000004163336    7B 14 AE 47 E1 7A 94 BF
-1.0000000000000000000000000    00 00 00 00 00 00 F0 BF
0.0000000000000000000000000     00 00 00 00 00 00 00 00

윈도우: (MSVC++ 6)
-0.0200000000000000000000000    7B 14 AE 47 E1 7A 94 BF
-1.0000000000000000000000000    00 00 00 00 00 00 F0 BF
0.0000000000000000000000000     00 00 00 00 00 00 00 00

왼쪽은 printf("%.25lf", number);로 출력되는 숫자이고 오른쪽은 그 바이트 표현입니다. 즉, 다른 계산 결과가 나온 게 아니라 애초에 printf의 출력 방법이 달라서 저런 결과가 나온다는 걸 알 수 있습니다. (아마 위에서 말씀하신 것도 이런 이유 때문인 것 같습니다.)

아래는 제가 사용한 테스트 코드입니다.

#include <stdio.h>

void print(double a) {
    int i;
    printf("%.25lf\t", a);
    for(i=0; i<sizeof(a); i++) {
        printf("%02hhX ", *(i+(char*)&a) & 0xff);
    }
    printf("\n");
}

int main() {
    double a;
    a = -0.02; print(a);
    a *= 50; print(a);
    a += 1.00; print(a);
    return 0;
}

- 토끼군