BioPlayground

🧬
목록으로

부동 소수점 — 0.1 + 1.1이 1.2가 아닌 이유

컴퓨터가 소수를 정확하게 표현하지 못하는 이유와, 실무에서 이 문제를 다루는 방법을 알아봅니다.

중급
|
5
|
검증 완료 (2026-07)
진행률0/20 (0%)

부동 소수점 — 0.1 + 1.1이 1.2가 아닌 이유

이 토픽을 마치면

"왜 0.1 + 0.2가 0.30000000000000004지?"라는 질문에 기술적으로 답할 수 있습니다.


이 코드를 실행하면 충격을 받습니다

python
print(0.1 + 0.2)
# 0.30000000000000004
javascript
console.log(0.1 + 0.2);
// 0.30000000000000004

Python이든 JavaScript든 Java든 C든 모든 프로그래밍 언어에서 같은 결과가 나옵니다. 버그가 아닙니다. 컴퓨터가 소수를 저장하는 방식의 근본적인 한계입니다.


왜 이런 일이 벌어지는가

컴퓨터는 모든 것을 **이진수(0과 1)**로 저장합니다. 정수는 정확하게 변환됩니다:

text
13 = 1101₂  (정확)

하지만 소수는 다릅니다. 0.1을 이진수로 바꾸면:

text
0.1 = 0.0001100110011001100110011... ₂  (무한 반복)

10진수에서 1/3 = 0.33333...이 무한 소수인 것처럼, 이진수에서 0.1은 무한 소수입니다. 컴퓨터는 무한한 숫자를 저장할 수 없으므로 어딘가에서 자릅니다. 이 "자름"이 오차를 만듭니다.


실무에서 진짜 문제가 되는 경우

python
# 가격 계산
price = 0.1 + 0.1 + 0.1
print(price == 0.3) # False!
# 반복 누적
total = 0.0
for _ in range(10):
total += 0.1
print(total) # 0.9999999999999999 (1.0이 아님!)

쇼핑몰에서 100원짜리 물건 10개의 합이 999원으로 나오면 고객은 신고합니다. 금융 시스템에서 1원이라도 안 맞으면 감사에 걸립니다.


어떤 소수는 정확하다

모든 소수가 오차를 갖는 것은 아닙니다:

python
print(0.5 + 0.25) # 0.75 (정확!)
print(0.125 + 0.0625) # 0.1875 (정확!)

0.5 = 1/2, 0.25 = 1/4, 0.125 = 1/8 — 이들은 2의 거듭제곱의 합으로 표현 가능해서 이진수로 정확하게 변환됩니다. 반면 0.1 = 1/10은 2의 거듭제곱으로 표현할 수 없어서 오차가 생깁니다.


해결 방법

1. 정수로 바꿔서 계산 — 가장 실용적

python
# 원 단위 대신 전 단위로 계산
price_in_jeon = 10 + 10 + 10 # 30전
total = price_in_jeon / 100 # 0.3원 (정확)

2. 비교할 때 오차 허용

python
# ❌ 절대 이렇게 비교하면 안 됨
if a == 0.3:
# ✅ 오차 범위 내에서 비교
if abs(a - 0.3) < 1e-9:
print("같다고 봅니다")
# Python 3.5+
import math
if math.isclose(a, 0.3):
print("같다고 봅니다")

3. Decimal 모듈 — 정밀도가 절대적으로 중요할 때

python
from decimal import Decimal
a = Decimal("0.1") + Decimal("0.2")
print(a) # 0.3 (정확!)
print(a == Decimal("0.3")) # True

문자열 "0.1"로 만들어야 합니다. Decimal(0.1)은 이미 부동 소수점 오차가 들어간 값을 넣는 것이므로 의미가 없습니다.


IEEE 754 — 소수를 저장하는 표준

모든 프로그래밍 언어가 같은 오차를 내는 이유는 IEEE 754라는 국제 표준을 따르기 때문입니다. 이 표준은 64비트(double precision)를 세 부분으로 나눕니다:

text
[부호 1비트] [지수 11비트] [가수 52비트]

52비트의 가수로 약 15~17자리의 유효 숫자를 표현합니다. 0.1의 이진 표현이 무한 소수이므로, 52비트에서 잘리면서 약 0.1000000000000000055511151231257827021181583404541015625가 됩니다.


다른 언어에서도 동일

java
// Java
System.out.println(0.1 + 0.2);  // 0.30000000000000004

// C
printf("%.17f\n", 0.1 + 0.2);   // 0.30000000000000004

// Go
fmt.Println(0.1 + 0.2 == 0.3)   // false

JavaScript에서는 모든 숫자가 IEEE 754 double이라 정수도 영향을 받습니다:

javascript
console.log(9007199254740992 + 1);  // 9007199254740992 (변화 없음!)
console.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991

이 한계를 넘는 정수에는 BigInt를 사용합니다.


실무 체크리스트

상황해결책
소수점 비교math.isclose() 또는 abs(a-b) < 1e-9
돈 계산Decimal 또는 정수 단위(센트, 전)
대용량 수치 계산float 그대로 (오차 무시 가능)
JSON 직렬화round(value, 10) 후 저장
데이터베이스DECIMAL 타입 사용

핵심 한 줄: 컴퓨터가 소수 계산을 틀리는 건 버그가 아니라 이진수의 근본적 한계입니다. 돈 계산은 Decimal이나 정수 단위로, 비교는 math.isclose()로 — 이 두 가지만 기억하면 됩니다.