topic★★★★★난이도 · 약 20분
숫자 표현 — 부동소수점·정수 오버플로
`0.1 + 0.2 !== 0.3`, 정수 53비트 한계, BigInt — '계산이 왜 안 맞나' 답.
#IEEE754#부동소수점#BigInt#정수오버플로#Decimal
왜 배우는가
금액 계산·주식 가격·좌표 비교에서 0.0000001 차이로 불량품 판정. IEEE 754의 물리적 한계를 알아야 올바른 자료형을 고른다.
컴퓨터의 실수는 이진 부동소수점(IEEE 754). 0.1 같은 10진 소수를 이진으로 정확히 표현할 수 없다. `0.1`은 실제로는 `0.1000000000000000055...` 저장되고, 덧셈할 때마다 오차 누적.
javascript
// 고전 함정
0.1 + 0.2 === 0.3 // false!!!
0.1 + 0.2 // 0.30000000000000004
// 해법 3가지
// 1) 소수점 반올림 (간단, 표시용)
Number((0.1 + 0.2).toFixed(10)); // 0.3
// 2) 정수 단위로 계산 (금액은 "원" 말고 "전")
const total = (10 * 100) + (20 * 100); // 센트·원 단위
// 출력할 때만 /100
// 3) 고정소수점 라이브러리 (금액·금융)
import Decimal from "decimal.js";
new Decimal("0.1").plus("0.2").toString(); // "0.3"
// 금액은 절대 float 말고:
// - 정수(최소 단위로) 또는
// - decimal 타입 (Postgres NUMERIC, JS Decimal)"주문 합계가 1원씩 틀려요" 버그의 근원. 결제·회계는 Decimal 또는 정수.
JS 정수의 숨은 한계. `Number`는 내부가 double(64비트 실수). 정확히 표현 가능한 정수는 ±2^53(≈ 9,007,199,254,740,992)까지. 그 이상은 오차 발생. Twitter/X의 트윗 ID, 비트코인 사토시 등은 이 범위를 넘는다.
javascript
Number.MAX_SAFE_INTEGER // 9007199254740991 = 2^53 - 1
Number.MAX_SAFE_INTEGER + 1 // 9007199254740992
Number.MAX_SAFE_INTEGER + 2 // 9007199254740992 ← 2를 더했는데 안 변함!
// 큰 정수는 BigInt (n 접미사)
const tweetId = 123456789012345678n;
tweetId + 1n === 123456789012345679n // true
// API에서 큰 ID를 받을 때
JSON.parse('{"id":123456789012345678}').id // 123456789012345680 ← 오염!
// 해법: 서버에서 문자열로 내려주기 {"id":"1234..."} → JS에선 문자열로 다룸
// Python은 정수 임의 정밀 (자동)
10 ** 100 # Python에선 OK, JS에선 Infinity"DB에서 받은 ID가 다름" 버그의 원인. 큰 정수 ID는 문자열로 다루거나 BigInt 사용.
실수 비교엔 `==` 금지, 허용오차(`epsilon`) 비교. `Math.abs(a - b) < 1e-9`. Claude가 생성한 금융·과학 계산 코드에 `===` 비교가 보이면 의심하라.
실기 드릴 2문항
code실기 드릴 · 코드 추적
JS: `0.1 + 0.2 === 0.3` 의 결과는?
pseudo
console.log(0.1 + 0.2 === 0.3);edit실기 드릴 · 단답형
JS에서 2^53을 넘는 정수를 오차 없이 다루기 위한 자료형은?