공부/Java

[공부/Java] 고정 소수점과 부동 소수점, 왜 컴퓨터는 소수 계산을 정확하게 못할까?

yulee_to 2022. 12. 28. 20:05

Java


고정 소수점 (Fixed Point)

10진수를 2진수로 바꾼후 그걸 소수점이 정해진 곳에 넣는 방식이다.

맨 앞 1자리는 부호 비트(sign bit)라 해서 0이면 양수, 1이면 음수를 의미한다.

소수점의 위치는 미리 정해두고, 비트를 채워넣고 남은 공간은 0으로 채워준다.

이런 고정 소수점 방식은 구현하기는 편리하지만 사용한느 비트 수 대비 표현 가능한 수의 범위 또는 정밀도가 낮기 때문에 실수를 다룰 필요가 있는 범용 시스템에서는 거의 안 쓰이고, 높은 정밀도가 필요 없는 소규모 시스템에서는 간혹 쓰인다.

부동 소수점 (Floating Point)

2진수로 변환한 결과를 그대로 넣지 않고 몇가지 과정을 거친다.

 

정규화 (Normalization)

2진수를 1.xxx * 2^n 꼴로 변환하는 것을 말한다.

정수부에 1만 남을 때까지 소수점을 이동시키고, 이동한 칸 수 만큼 n 자리에 집어 넣으면 된다.

 

IEEE 754 부동소수점 표현

IEEE 표준에 따르면 부동소수점 방식으로 실수를 저장하는 데는 32비트, 또는 64비트가 사용된다.

자바에서 32비트 부동소수점은 float, 64비트 부동소수점은 double이다.

 

두 타입 모두 부호 비트로 1bit를 가지고, 지수부(exponent), 가수부(fraction)을 갖는다.

지수부에는 정규화된 식에서의 n에 해당하는 수에 bias라고 하는 지정된 숫자 127을 더한 값을 2진수로 바꾸어 넣어준다.

가수부에는 정규화된 식에서의 0.xxx...에 해당하는 부분을 왼쪽 숫자부터 차례대로 넣어주고 남는 자리는 0으로 채운다.

오른쪽으로 소수점을 옮겨 정규화를 한 경우에는 n이 음수가 되기 때문에 bias라는 값을 써 지수가 음수가 되는 경우를 방지한다.

32비트 float은 부호(1비트), 지수부(8비트), 가수부(23비트)이고, 64비트 double은 부호(1비트), 지수부(11비트), 가수부(52비트)로 이루어져 있다.

 

부동 소수점 방식의 오차

부동 소수점을 사용하면 고정 소수점 방식보다 훨씬 더 많은 범위까지 표현할 수 있다는 장점이 있지만 부동 소수점에 의한 실수의 표현은 항상 오차가 존재한다는 단점을 가진다.

정규화 식을 이용하면 표현할 수 있는 범위는 늘어나지만, 10진수를 정확하게 표현할 수는 없게 된다. 예를 들어 10진수 0.3을 2진수로 변환하면 0.0100110011...처럼 특정 수가 무한히 반복된다. 따라서 컴퓨터가 실수 부분을 표현할 수 있는 비트수를 다 써버리게 되어 근사치로 표현된다.


참고 자료 :

http://www.tcpschool.com/cpp/cpp_datatype_floatingPointNumber

https://gguguk.github.io/posts/fixed_point_and_floating_point/

728x90