새소식

인기 검색어

개발일기

부동소수점의 한계와 BigDecimal

  • -

부동소수점을 이해하려면 우선 디지털과 아날로그의 차이부터 이해해야 한다.

 

우리가 살고 있는 아날로그 세상의 수는 연속적(sequential)하지만, 디지털 세계의 수는 이산적(discrete)이다.

 

여기서 연속적이라는 의미는 값이 딱 나눠떨어지는 것이 아니라 무한대의 소수가 존재할 수 있다는 의미이다. 예를 들어 0.111011101110...과 같은 수가 존재할 수 있다.

 

이산적이라는 것은 손가락 하나, 둘과 같이 연속적인 것이 아닌 딱딱 떨어지는 수들이 존재함을 의미한다. 디지털 세계는 우리가 모두 알다시피 0과 1로 이루어져 있다.

 

따라서 디지털 세계에서 아날로그의 소수를 표현하기 위해 노력들을 해왔는데, 그중 하나가 IEEE 754다. 이는 부동소수점(floating point)을 정의한 표준이다.

 

부동소수점을 계산할 때는 수를 '지수부'와 '가수부'로 나누어 계산한다. 따라서 가수부가 표현할 수 있는 범위가 곧 (이진수)소수점 자리수를 의미한다.

 

출처 : https://devocean.sk.com/blog/techBoardDetail.do?ID=165270

 

 

가수부가 넘어가는 수는 플랫폼에 따라 다음과 같은 규칙들 중 하나를 적용해 반올림을 적용한다.

 

출처 : https://devocean.sk.com/blog/techBoardDetail.do?ID=165270

 

이 말은 즉슨, 부동소수점으로 표현할 수 있는 것은 정확한 값이 아닌 '근사치'를 사용한다는 것이다. 이러한 점 때문에 부동소수점은 == 비교시 값이 매번 달라진다는 문제를 가진다.

 

자세한 내용을 이해하고 싶다면 다음 글을 읽어보면 좋다. 많은 글들 중 가장 이해하기 쉽고 잘 설명해주고 있는 글이라고 생각된다.

- 부동 소수점의 이해 (1부) : https://devocean.sk.com/blog/techBoardDetail.do?ID=165270

- 부동 소수점의 이해 (2부) : https://devocean.sk.com/blog/techBoardDetail.do?page=&boardType=undefined&query=&ID=165276&searchData=&subIndex=

- [System Programming] 02. 부동 소수점(Floating Point)의 표현 (2) : https://roadtodeveloper.tistory.com/31

 

부동소수점이 가지고 있는 문제는 또 있다. 바로 지수부가 커질수록 표현할 수 있는 소수점 자리수가 달라져 정확도가 차이난다는 점이다.

 

IEEE 인코딩 범위 : https://roadtodeveloper.tistory.com/31

 

6비트 체계에서 IEEE 방식과 유사하게 실수를 표현할 때 표현할 수 있는 실수 분포 : https://roadtodeveloper.tistory.com/31

 

 

위 그래프를 보면, 확실하게 값이 커질수록 표현할 수 있는 수의 밀도가 줄어든다. 이러한 차이가 나는 이유는 아까 위에서 언급했던 지수부와 가수부가 정해져 있다는 것에 있다.

 

 

여기서 가수가 표현할 수 있는 범위는 가장 큰 숫자 자리에서부터 시작한다. 예를 들어, 1.0001 * 2^4 이라면 10001과 같다는 의미이다. 그런데 float의 경우 가수가 23bits로 이루어져 있다. 따라서 표현할 수 있는 지수 기준 맨 윗자리에서 23째 자리까지 표현 가능하다고 할 수 있다.

 

이러한 특징 때문에 float일 경우 지수가 23이 넘어가면 소수점을 표현할 수 없다. 0.0 ... 01(23째 자리까지) * 2 ^ 23은 결국 1이기 때문이다.

 

java에서 간단하게 실험해 보면 다음과 같은 결과를 얻을 수 있다.

 

여기서 의문이 하나 생긴다. 단일정밀도(float, 32bits)의 경우 지수부가 8bits기 때문에 표현할 수 있는 지수의 범위의 크기는 (2^7 - 1) * 2이고 (편향된 지수, biased exponent를 사용하기 때문. 궁금하면 참조한 부동 소수점의 이해 (2부)를 참고하자.) 정확히는 -126 ~ +127이다.

 

위에서 본 결과에 의하면 지수가 23 이상이면 소수점을 표현할 수 없게 되는데 왜 부동소수점을 사용하는 걸까? 정수를 표현하려는데 부동소수점을 사용하게 되면 다음과 같은 단점들이 발생한다.

1. 오차가 생긴다.

2. 정규화 등 연산이 추가로 들어가야 하기 때문에 비싼 비용을 지불해야 한다.

 

다행히도 Stack Overflow에서 나와 같은 의문을 가지고 있는 사람이 있어 그 사람의 질문을 가져와 봤다.

 

https://stackoverflow.com/questions/40775949/why-do-higher-precision-floating-point-formats-have-so-many-exponent-bits

 

Why do higher-precision floating point formats have so many exponent bits?

I've been looking at floating point formats, both IEEE 754 and x87. Here's a summary: Total Bits per field Precision Bits Sign Exponent Mantissa Single 32...

stackoverflow.com

나는 간단하게 IEEE(전기전자공학자협회(Institute of Electrical and Electronics Engineers))는 컴퓨터에 국한된 것을 정하는 단체가 아니기 때문에 어른들의 사정에 의해 저렇게 설계했다 정도로 이해했다.

 

아무튼, 위 내용을 정리하자면 다음과 같다.

1. 부동소수점은 연속적인 실수를 반올림해서 표현하기 때문에 오차가 발생한다.

2. 부동소수점은 값의 절대값이 클수록 오차율이 커진다.

 

Java에서는 이러한 특성 때문에 돈과 같이 정확한 값을 요구하는 경우, 부동소수점이 아닌 BigDecimal을 사용한다.

 

그렇다면 BigDecimal은 어떻게 정밀도를 보장하는 걸까?

 

BigDecimal 클래스 안을 까보면 내부에서 BigInteger라는 객체를 사용함을 볼 수 있다. 그리고 BigInteger의 주생성자를 보면 들어온 값을 int형 배열에 집어넣고 있음을 확인할 수 있다.

 

 

이러한 방법을 임의 정밀도(arbitrary-precision)이라 부른다. 이 방법은 이론적으로 모든 길이의 소수를 표현할 수 있고, 최신 언어에서는 웬만해선 다 제공된다고 한다.

- Arbitrary-precision : https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic

 

그럼 정말 모든 길이의 소수를 표현할 수 있는 걸까? 물론 제약이 존재한다.

 

 

 

위와 같은 수치는 한 배열에 들어갈 수 있는 최대 한도인 (근사치)2^31 - 1에 못미치는 수치이다. (idx를 표현할 때 int를 사용하기 때문에 int 크기 만큼의 배열이 들어갈 수 있다.)

 

그런데 아래 글을 읽어보니 JVM 모델마다 표현할 수 있는 idx 크기가 다른 것 같다. 그래서 적당히 어른들의 사정이 있겠구나 생각하고 있다.

- Maximum Size of Java Arrays : https://www.baeldung.com/java-arrays-max-size

 

참조

- 부동 소수점의 이해 (1부) : https://devocean.sk.com/blog/techBoardDetail.do?ID=165270

- 부동 소수점의 이해 (2부) : https://devocean.sk.com/blog/techBoardDetail.do?page=&boardType=undefined&query=&ID=165276&searchData=&subIndex=

- [System Programming] 02. 부동 소수점(Floating Point)의 표현 (2) : https://roadtodeveloper.tistory.com/31

- Why do higher precision floating point foramts have so many exponent bits : https://stackoverflow.com/questions/40775949/why-do-higher-precision-floating-point-formats-have-so-many-exponent-bits

- Arbitrary-precision : https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.