핵심 요약
- 개발자들 사이에서 0.1 + 0.2가 0.3이 되지 않는 부동소수점 오차 문제는 유명하지만, 소수점 두 자리 덧셈을 전수 조사하면 매우 규칙적인 오차 패턴이 나타납니다.
- 64비트 부동소수점의 비트 구조와 짝수 반올림 규칙, 10진수 문자열 변환 알고리즘이 결합되면서 이러한 계산 결과가 도출됩니다.
- 일반적인 영수증 금액 범위(약 70조 달러 미만)에서는 센트 단위 계산 시 오차가 어떻게 상쇄되는지 수학적으로 규명했습니다.
요약 개발자들 사이에서는 돈이나 영수증 계산을 할 때 프로그래밍 언어의 기본 부동소수점(float)을 쓰지 말라는 것이 거의 상식처럼 통합니다. IEEE 754 배정밀도 부동소수점 표준에서는 10진수 소수를 2진수로 정확히 표현할 수 없어 반올림 오차가 발생하기 때문입니다. 대표적으로 파이썬 등에서 0.1 + 0.2를 입력하면 0.3이 아니라 0.30000000000000004가 출력되는 현상이 유명합니다.
하지만 한 개발자가 파이썬 REPL에서 소수점 두 자리(센트 단위) 금액들을 더해보니 생각보다 오차 없이 깔끔하게 맞아떨어지는 경우가 많다는 점에 주목했습니다. 실제로 0.01부터 1.00까지의 모든 0.01 배수 조합을 더해 출력값이 원래 값보다 큰지, 작은지, 정확한지를 시각화해보니 매우 규칙적이고 독특한 패턴이 나타났습니다.
이 현상을 이해하려면 64비트 배정밀도 부동소수점의 구조를 들여다봐야 합니다. 64비트는 부호 1비트, 지수부 11비트, 가수부 52비트(숨김 비트 1개 포함)로 구성되며, 가장 마지막 비트의 유효 가치를 ULP(Unit in the Last Place)라고 부릅니다. 파이썬에서 0.1 + 0.2를 계산할 때, 먼저 0.1과 0.2를 각각 가장 가까운 부동소수점으로 변환한 뒤 둘을 정확히 더하고, 그 결과를 다시 가장 가까운 부동소수점으로 반올림합니다. 공교롭게도 이 덧셈 결과는 양쪽 부동소수점과 거리가 정확히 같아 짝수 가수부로 올림되는 규칙이 적용됩니다.
여기에 화면 출력 시 적용되는 10진수 변환 알고리즘(Steele & White 기준)이 더해집니다. 출력값은 다시 부동소수점으로 입력했을 때 원래 값이 나와야 하고, 가장 짧아야 하며, 실제 부동소수점 값에 가장 가까워야 한다는 규칙을 따릅니다. 글쓴이는 약 70조 달러(2의 46제곱) 미만의 일상적인 금액 범위에서는 부동소수점 간격이 센트 단위보다 조밀해 특정 조건에서 오차가 상쇄되거나 정확히 표현되는 이유를 수학적으로 분석했습니다.
Sponsored · 광고