Algorithmic Trading

부동소수점 수, 정밀도 이야기

○@ 2021. 2. 18. 12:00

 

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 에서 제공하는 정밀도 높은 변수를 사용합니다.

www.boost.org/doc/libs/1_72_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/cpp_dec_float.html

 

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

을 구하는 거죠.

 

 

 

 

이게 무슨 시덥잖은 주제로 글을 쓰는 건가 싶다면,

제가 최근에 밤샘작업과 야근이 많아서 피폐해진 탓으로 돌리고 싶네요.

개인적인 개발작업들과 블로그 글도 써야 하는데 말이죠.

 

 

 

아...... 남이 싸고 도망간 똥 치우느라 힘겹습니다.