부동소수점이 가지고 있는 문제는 또 있다. 바로 지수부가 커질수록 표현할 수 있는 소수점 자리수가 달라져 정확도가 차이난다는 점이다.
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에서 나와 같은 의문을 가지고 있는 사람이 있어 그 사람의 질문을 가져와 봤다.