2.3-0.3이 왜 1.9999999999999998일까

개발자와 콩나무·2024년 6월 11일

개발공부

목록 보기
7/14

high = 2.3
low = 0.3
result = high - low
print(result)  # 1.9999999999999998

빅분기 연습 문제를 풀던 중, 2.3-0.3을 계산한 결과가 2.0이 아닌 1.9999999999999998로 나오는 것을 발견했다. 왜 이런 결과가 나오는 것일까? (전공 공부할 때도 고민하지 않았던 걸 딴짓거리로 삼아본다 ^^)

부동 소수점이란?

문제는 컴퓨터에서 실수를 표현하는 방식에서 시작된다. 부동 소수점이란, 매우 큰 수나 매우 작은 수를 다루기 위해 사용되는 방식이다. 소수점 이하의 값을 포함하는 수를 저장하고 계산할 때 사용되는 것이 바로 부동 소수점!

표현 방식

(가수)×(밑수)^(지수)

예를 들어, 123.45 = 1.2345*10^2가 되는 것이다.

부동 소수점의 한계

부동 소수점 수는 IEEE 754 표준에 따라 정의되는데 단정밀도와 배정밀도로 나뉜다.

IEEE 표준은 부호비트, 지수, 유효숫자로 나뉜다.

  • 단정밀도 : 부호 비트(1비트), 지수(8비트), 유효숫자(23비트)
  • 배정밀도 : 부호 비트(1비트), 지수(11비트), 유효숫자(52비트)

이때 부동 소수점 숫자가 유한한 비트로 표현되기 때문에 정밀도 제한이라는 문제가 생긴다. 예를 들어, 0.1 같은 소수는 이진 부동 소수점으로 정확하게 표현될 수 없으므로 근사치로 저장되는 등 일부 실수 표현에서 정확성이 떨어진다는 것이다.

자연스레, 연산에서 오차에서가 생길 수밖에 없고 부동 소수점으로 표현하는 과정에서 오차가 발생한 수가 계산과정에 많이 포함될수록 전체 계산 결과에서의 오차도 늘어날 것이다.

마지막으로, 오차를 감안하고서라도 최대한 많은 숫자를 표현하고자 한 것이 부동 소수점이나 결국 가용 비트에 한계가 있기 때문에 매우 큰 수나 매우 작은 수를 표현할 때 오버플로(overflow)나 언더플로(underflow)가 발생할 수 있다.

2.3-0.3=1.9999999999999998가 되는 과정

먼저, 2.3과 0.3은 10진수이다. 부동 소수점은 이진 소수점으로 표현되기 때문에 2.3과 0.3을 각각 이진 소수점으로 변환해보자.

2.3

2.0 : 이진으로 10
0.3 이진으로 0.0100110011... (무한소수)

0.3

0.3 : 이진으로 0.0100110011... (무한소수)

사실, 이렇게 변환한다고 하더라도 0.3의 이진 형태인 0.0100110011... (무한소수)라는 동일한 값을 빼는 것이기 때문에 2.0이 나와야하지 않나..싶지만, 아쉽게도 비트의 유한성 때문에 근사치로 바뀌게 된다. 여기서 오차가 발생한다고 볼 수 있다.

따라서, 이진 소수점에서의 계산 결과를 10진수로 변환하면 2.0이 아닌 .9999999999999998 같은 근사치가 나오게 되는 것이다.

2.3-0.3=2.0로 만들겠다

문제를 해결하는 방법은 의외로 간단하다. (in python)
반올림 ^^

rounded_result = round(result, 10)  # 소수점 이하 10자리로 반올림
print(rounded_result)  # 2.0

해결하는 법이 허무한 감이 있지만, 뭐든지 과정이 어렵지 끝나면 간단한 것 같다..ㅎㅎ;;

profile
무럭무럭 자라는 개발자와 콩나무 🌱 콩 한 쪽이라도 기록하자! 개발 실력 향상을 위한 백엔드와 머신러닝, 자격증 공부기록

0개의 댓글