[CS관련]소수의 저장

원대한·2023년 10월 28일
1
post-thumbnail

1. 아래 수식의 결과는?

A = 0.1
B = 1.1
print(A + B == 1.2)

위와 같이 코드를 작성한 뒤 실행을 하면 False 가 뜨는 것을 볼 수 있다. 일반적인 상식으로는 0.1 + 1.1 은 1.2 가 맞지만 대부분의 언어에서 위의 논리식의 결과는 '거짓' 이 나온다.

이는 소수가 컴퓨터의 메모리에 저장되는 방식에 원인이 있다. 소수가 메모리에 저장될 때는 다음과 같이 저장된다.

1) 일단 저장하고자 하는 소수를 이진수로 바꾼다.

ex) 68.625
정수부 68 은 그대로 이진수로 변환한다.

68 = 64 + 4 -> 100 0100

소수부 0.625 에 2를 곱하는데 그 결과가 1로 떨어질 때까지 혹은 똑같은 소수점이 나올 때까지 반복한다.

0.625 × 2 = 1.250
0.250 × 2 = 0.500
0.500 × 2 = 1.000
. . .

위에서부터 차례로 가져오면 101 이 되며 정수부와 소수부를 합치면 1000100.101 이다.
68.625 -> 1000100.101 (이진수)

한 가지 예시를 더 들어 보면
ex) 125.3

125 = 64 + 32 + 16 + 8 + 4 + 1 -> 111 1101
0.3 x 2 = 0.6
0.6 x 2 = 1.2
0.2 x 2 = 0.4
0.4 x 2 = 0.8
0.8 x 2 = 1.6
첫번째 결과의 소수점(.6)과 동일하므로 중단

125.3 -> 1111101.01001 이 됨을 알 수 있다.

2) 이진수를 메모리에 저장

위에서 바꾼 이진수를 메모리에 바로 저장해도 되겠지만 더하기나 빼기 등의 연산을 쉽고 빠르게 하기 위해 다음 형식에 따라 저장한다.

메모리에 숫자 하나 당 32 칸 정도를 준비해 놓고 첫번째 칸에 부호를 결정하는 숫자를 저장한다.(양수면 0 음수면 1)

그리고 101.001 같은 숫자를 1.01001 x 22 와 같이 표현해준다.

소수점 뒤의 수 .01001 을 mantissa 부분이라 하고 32칸 중 맨 뒤의 23 칸에 밀어넣는다.

그리고 22의 지수 부분 2 + 127 -> 10000001 를 부호 표현하는 뒤 8 칸 자리에 넣어준다.

그러면 0|10000001|01001 와 같이 메모리에 저장된다.

이것이 컴퓨터가 소수를 메모리에 저장하는 방식이다. 하지만 이 방식을 통하여 이진수로 바꾸었을 때 순환소수가 되는 경우 오류가 생기게 된다. 0.1 같은 수를 2진수로 변환하면 0.00011001100110011001100110011.... 과 같이 떨어지지 않는 무한한 소수가 되고 이것을 32 칸에 저장하려면 중간에 컷을 시켜 저장할 수 밖에 없다. 그래서 변수에 0.1 을 저장하더라도 0.1과 비슷한 수를 저장한 것일 뿐 0.1 이 아니게 되므로 0.1 + 1.1 == 1.2 라는 수식은 거짓이 되는 결과가 나온다.

따라서 프로그램 제작 할 때 오차 없이 정확히 계산하는 기능을 만들고 싶다면 float 자료형을 쓰지 말고 정수로 보관할 필요가 있다. 예를 들어 5.3 달러와 같은 수를 저장할 때 5300 센트로 바꿔 저장하는 것이 좋다. 만약 float 를 써야할 때는 반올림 문법을 적절하게 사용하는 것이 해결책일 수 있다. 또한 double 자료형을 쓸 수 있는데 이것은 숫자 1개 당 64칸 을 사용하게 하여 오차를 줄일 수 있는 방법이다.(단점 메모리 용량 2배 필요)

profile
데이터분석 및 개발, 금융 관련

0개의 댓글