정리

부동소수점 처리 방법

gilchris 2020. 2. 13. 02:05

얼마전에 회사에서 어떤 분이 javascript에서 1 - 0.99 을 했는데 0.010000000000000009 이 나온다며 물어보셨다. (실제로는 비슷한 다른 거 였던 거 같은데 어쨌든..)
이는 부동소수점. 그러니까 float나 double 형에서 실수를 저장하는 방식 때문에 발생한다.

이런 내용은 조금만 검색하면 나온다. 하지만, 원인과 동작방식을 설명하는 글은 많지만 정작 실무에서 어떻게 처리하는게 좋을지에 대한 글이 없어서 여기에 남겨본다.

반올림, 올림, 내림

대부분의 부동소수점 문제는 소수점 아래의 값에서 발생한다. 많은 프로젝트에서는 사실 어느정도 오차가 있어도 문제없는 경우가 많다. 이럴 때에는 소수점 아래를 반올림, 올림, 내림해서 값을 정수로 만들어서 쓰면된다.
대부분의 언어에서 기본 라이브러리로 round(반올림), ceil(올림), floor(내림) 등등의 이름으로 지원하고 있으니 이걸 이용하면 된다.
그리고, 반올림, 올림, 내림을 할 때에는 계산이 다 끝난 후에 하지말고, 계산 중에 소수가 나왔을 때 바로 처리하는게 문제 발생의 여지가 적다.

10을 곱했다가 나누기

소수점 이하 일부의 값이 필요한 경우에 이용한다. 소수점 이하의 필요한 자리수 만큼 10을 곱해서 필요한 부분을 정수부로 올리고 위의 반올림, 올림, 내림을 이용해서 소수부를 자른다. 그 다음에 다시 곱했던 만큼 10으로 나누면 오차가 나는 부분을 잘라낼 수 있다.
예를들어, 0.987654321이라는 수에서 0.98만이 필요하다면, 두 자리가 필요하니 10의 2제곱, 즉, 100을 곱해서 98.7654321을 만들고 내림을 해서 98로 만들고 곱했던 100으로 나눠서 0.98로 만드는 방식이다.
언어 중에서는 반올림, 올림, 내림 함수가 소수점을 지원하는 경우도 있다. 언어에서 지원을 한다면 당연히 그것을 사용하면 된다.

정밀한 계산을 지원하는 라이브러리 사용하기

프로젝트 중에는 실제로 소수점 자리 깊은 곳까지 정밀한 계산이 필요한 경우도 있다. 대부분의 유명한 언어들에는 이런 계산을 도와주는 라이브러리들이 있다.
javascript에는 decimal.js가 유명하고, python에서는 언어에서 기본으로 decimal이라는 모듈을 지원한다. java도 JDK 내에 java.math.BigDecimal 라는 클래스를 이용하면 된다.
당연하게도 정밀한 계산을 하면 단순히 반올림, 올림, 내림을 하는 것보다 프로그램이 사용하는 자원이 늘어나게 된다. 이런 라이브러리의 사용은 반드시 필요한지 고민해보고 사용해야 한다.

 

이상 부동소수점 문제를 처리하는 대표적인 방법 몇가지를 알아보았다. 이 외에도 각자만의 방법이 있을 수도 있고, 게임이나 인공지능에서처럼 GPU를 이용한 처리를 할 수도 있겠다.