부동소수점 수, 정밀도 이야기
C/C++ 에서 제공하는 float, double 변수는 IEEE754 형식의 single / double precision 에 맞춘 변수일뿐이고,
실제로 소수점 연산의 정밀도는 보장하지 않습니다.
===========================================================================
// Floating-point_number_precision.c
// Compile options needed: none. Value of c is printed with a decimal
// point precision of 10 and 6 (printf rounded value by default) to
// show the difference
#include <stdio.h>
#define EPSILON 0.0001 // Define your own tolerance
#define FLOAT_EQ(x,v) (((v - EPSILON) < x) && (x <( v + EPSILON)))
int main() {
float a, b, c;
a = 1.345f;
b = 1.123f;
c = a + b;
// if (FLOAT_EQ(c, 2.468)) // Remove comment for correct result
if (c == 2.468) // Comment this line for correct result
printf_s("They are equal.\n");
else
printf_s("They are not equal! The value of c is %13.10f "
"or %f",c,c);
}
[ docs.microsoft.com/ko-kr/cpp/build/why-floating-point-numbers-may-lose-precision?view=msvc-160 ] 에서 발췌
===========================================================================
위에서 보면, float 변수에서는 1.345 + 1.123 == 2.468 조차도 보장하지 못합니다.
double 변수에서도 자릿수만 조금 더 늘어날 뿐이고 비슷한 현상을 보입니다.
주식시장에서는 소수점 몇째자리 같은 건 중요하지 않다! 라고 생각하실 수 있겠지만,
여러 가지 지표를 사칙연산으로 계산하다 보면 [ 오차의 전파 ] 라는 것이 생깁니다.
결국은 사소한 값들이 누적되어 결국 큰 값이 틀어지게 되거나 큰 그림을 망치게 되기도 합니다.
그래서 요새 나오는 언어들에서는 Decimal, 혹은 BigDecimal 모듈? 패키지들을 제공하기도 하고요.
C/C++ 에서도 여러 가지 선택을 할 수 있긴 한데,
저는 boost library 에서 제공하는 정밀도 높은 변수를 사용합니다.
cpp_dec_float - 1.72.0
#include namespace boost{ namespace multiprecision{ template class cpp_dec_float; typedef number > cpp_dec_float_50; typedef number > cpp_dec_float_100; }} The cpp_dec_float back-end is used in conjunction with number: It acts as an entirely C++ (header on
www.boost.org
typedef number<cpp_dec_float<50> > cpp_dec_float_50;
위와 같이 정의한 숫자는 소수점 50째자리까지 정밀도를 보장하기 때문입니다.
그런데, 저런 라이브러리를 사용하다 보니,
어제는 갑자기 0.0025, 0.0005 단위로 modulo (나눗셈의 나머지) 를 구하는 함수가 없는 걸 깨닫고
// C/C++ 의 기본 float, double 용도의 modulo 함수로는 fmod 가 있습니다.
한참을 구현하느라 삽질을 했더랍니다.
저게 무슨 연산이냐면,
0.0007 modulo 0.0005 == 0.0002
0.0108 modulo 0.0005 == 0.0003
을 구하는 거죠.
이게 무슨 시덥잖은 주제로 글을 쓰는 건가 싶다면,
제가 최근에 밤샘작업과 야근이 많아서 피폐해진 탓으로 돌리고 싶네요.
개인적인 개발작업들과 블로그 글도 써야 하는데 말이죠.
아...... 남이 싸고 도망간 똥 치우느라 힘겹습니다.