회사 동료가 와서 이런 문제를 어떻게 해결해야 하는지 물어보네요.
이렇게 하면 d1의 값이 19.850000381469727 게 됩니다.
d2의 값이 19.850000000000001 인 것과는 완전 다르죠...
문제는 이렇게 구해진 d1을 수식에서 백분율로 사용하면서 생겼습니다.
원치않는 수치가 나오는 것이죠.
디스어셈블리로 코드를 확인하면 별 다른 것 없이
형을 변환하는 명령을 호출할 뿐입니다.
즉, 이건 컴파일러의 문제가 아니라는 것이죠.
그래서 이런 문제를 해결하면서 이전 코드의 수정을 최소화 한다면...
이런 방법 정도로 생각됩니다.
(BS에게 질문을 던진 동료는 그냥 백분율이기 때문에 100 곱해서 정수로 형변환해서 우회하기로 했지만요...)
결과는 잘 나오는데 어셈블리 코드를 보면 상당히 늘어나는 것을 알 수 있습니다.
return (double)f;
long long n = long long(f);
return n + long long((f - n) * 1000000) / 1000000.0;
처음부터 double을 쓰면 문제가 안되겠지만...
기존 시스템이 float를 쓰고 있고 여기에 추가되는 일부 코드가 long long과 double을 사용하는 경우에는 발생할 수 있는 문제입니다.
float f = 19.85f; double d1 = double(f); double d2 = 19.85;
이렇게 하면 d1의 값이 19.850000381469727 게 됩니다.
d2의 값이 19.850000000000001 인 것과는 완전 다르죠...
문제는 이렇게 구해진 d1을 수식에서 백분율로 사용하면서 생겼습니다.
원치않는 수치가 나오는 것이죠.
디스어셈블리로 코드를 확인하면 별 다른 것 없이
형을 변환하는 명령을 호출할 뿐입니다.
즉, 이건 컴파일러의 문제가 아니라는 것이죠.
그래서 이런 문제를 해결하면서 이전 코드의 수정을 최소화 한다면...
이런 방법 정도로 생각됩니다.
(BS에게 질문을 던진 동료는 그냥 백분율이기 때문에 100 곱해서 정수로 형변환해서 우회하기로 했지만요...)
#includeusing namespace std; class F32 { public: F32() : f(0.0f) {} F32(float s) : f(s) {} F32& operator=(float const & s) { f = s; return *this; } double operator*(double const & s) const { return s * double(*this); } double operator/(double const & s) const { return s / double(*this); } double operator+(double const & s) const { return s + double(*this); } double operator-(double const & s) const { return s - double(*this); } bool operator==(double const & s) const { return (double(*this) == s); } operator float() const { return f; } operator double() const { long long n = long long(f); return n + long long((f - n) * 1000000) / 1000000.0; } private: float f; }; int main(void) { float f = 19.85f; F32 tf = 19.85f; long long d1 = long long(double(tf) * 3370000000000LL); long long d2 = long long(tf * 1.0 * 3370000000000LL); long long d3 = long long(double(f) * 3370000000000LL); long long d4 = long long(f * 1.0 * 3370000000000LL); cout << d1 << endl; cout << d2 << endl; cout << d3 << endl; cout << d4 << endl; cout << (tf == 19.85) << endl; /* output: 66894500000000 66894500000000 66894501285552 66894501285552 1 */ return 0; }
결과는 잘 나오는데 어셈블리 코드를 보면 상당히 늘어나는 것을 알 수 있습니다.
return (double)f;
mov rax,qword ptr [this] movd xmm0,dword ptr [rax] cvtps2pd xmm0,xmm0
long long n = long long(f);
return n + long long((f - n) * 1000000) / 1000000.0;
mov rax,qword ptr [this] cvttss2si rax,dword ptr [rax] mov qword ptr [n],rax pxor xmm0,xmm0 cvtsi2sd xmm0,qword ptr [n] pxor xmm1,xmm1 cvtsi2ss xmm1,qword ptr [n] mov rax,qword ptr [this] movss xmm2,dword ptr [rax] subss xmm2,xmm1 movaps xmm1,xmm2 mulss xmm1,dword ptr [__real@49742400 (13F0E796Ch)] cvttss2si rax,xmm1 pxor xmm1,xmm1 cvtsi2sd xmm1,rax divsd xmm1,mmword ptr [__real@412e848000000000 (13F0E7940h)] addsd xmm0,xmm1
처음부터 double을 쓰면 문제가 안되겠지만...
기존 시스템이 float를 쓰고 있고 여기에 추가되는 일부 코드가 long long과 double을 사용하는 경우에는 발생할 수 있는 문제입니다.

by BSPFP