본문 바로가기

Study/Computer Science

0.1 + 0.2 != 0.3은 true인가?

잘 알려졌듯이 많은 프로그래밍 언어가 true로 평가한다. 재밌는 사실이다. 재미없는 부분도 있는데, 그 이유를 기술 면접에서 묻는 경우가 있다는 풍문이 들린다는 점이다.

 

개인적으로 이건 CS 지식이 아니라 수학 문제라고 생각한다. 극단적인 시점에서 대충 보면 중학교 수준의 문제기도 하다.

 

우선 숫자의 표현 한계에 대해 생각해보자. 모든 자연수는 2의 거듭제곱의 유한 급수(finite series)로 표현할 수 있고(존재성), 그것이 유일하다(유일성). 사실 증명은 안 해봤는데 그렇게 어려울 것 같지는 않다. 

임의의 자연수 n이 존재한다고 하자. 자연수는 2로 나눌 때마다 나머지가 0이거나 1일 것이다. 이걸 몫이 0이 되는 순간까지 반복하면, 짜잔. 2의 거듭제곱에 대한 급수로 자연수 n을 표현할 수 있게 된다. 이때 나머지가 0이거나 1이므로 급수의 계수 또한 0이거나 1이다. 유일성은 다른 계수의 급수가 존재한다고 가정하고 귀류법으로 증명하면 되지 않을까? 계수가 0이거나 1뿐이라는 가정에서 모순이 유도될 것 같다.

하지만 유리수는 그렇지 않다. 임의의 유리수가 모두 이진수의 유한 급수로 표현되지는 않을 것이다.

자세한 증명이 없어도 직관적으로 안 될 것 같아보인다. 임의의 자연수는 최소 단위인 1을 더하는 것만으로 만들어낼 수 있지만 유리수는 오밀조밀해서 눈금의 최소 단위랄 게 존재하지 않아 그게 불가능하니까.

그래도 이렇게 퉁치고 넘어가면 조금 아쉬우니 생각을 더 해보자. 좋은 예시가 있을까? 0.05로 해볼까? 0.05 = 1/20 = 1/(4*5) = 1/(2^2 * 5)이다. 만약 이것이 2의 거듭제곱의 유한 급수로 표현된다면, 적당한 n에 대해 양변에 2^n을 곱했을 때 정수가 되어야 한다. 하지만 1/20에 2^n을 아무리 곱해도 분모의 5는 사라지지 않는다. 따라서 0.05는 이진수의 유한소수로 표현될 수 없다.


일반화하면, 기약분수인 유리수 p/q가 이진 유한소수로 표현 가능한 필요충분조건은 q가 2의 거듭제곱이어야 한다는 것이다. 즉 0.5, 0.25, 0.125와 같은 숫자들은 exact한 연산이 가능할 것이다.


중학교 수학과 유비를 해보면 더욱 간단하다. 십진법에서 2와 5 이외의 소인수가 기약분수 형태에서 분모에 남아있다면, 예를 들어 1/3 = 0.333…이 무한소수인 것처럼, 이진법에서는 2 이외의 소인수가 기약분수 형태에서 분모에 남아있을 경우 무한소수가 된다. 예컨대 0.1 = 1/10 = 1/(2*5)는 이진법에서 무한소수다. 표현 체계가 달라지면 "간단한" 수와 "복잡한" 수의 기준도 달라지는 것이다.


이것이 바로 부동소수점 연산에서 0.1 + 0.2 != 0.3이 true로 평가되는 현상이 발생하는 근본적인 이유다. 컴퓨터는 이진법을 사용하고, 소수 또한 이진법으로 나타낼 수밖에 없으며, 십진법에서 깔끔하게 떨어지는 0.1은 이진법에서 무한소수라 유한한 비트로는 정확히 표현할 수 없으므로.

 

부동소수점의 sign, mantissa, exponent는 중요한 내용이지만 여기서 다루지는 않겠다. 그런 게 이 문제와 관계가 있는 건 아니니까.

'Study > Computer Science' 카테고리의 다른 글

[HTTP] Stateless  (0) 2024.05.02
인터페이스  (0) 2024.04.25
프로그래밍 패러다임  (0) 2024.04.15
자료형, 메모리, 그리고 Python [2]  (0) 2024.04.07
자료구조  (0) 2024.04.05