ONE QUESTION AT A TIME.

천천히 생각하고, 분명하게.

TODAY’S QUESTION512 / 1500

0.1을 천 번 더한 부동소수점 합이 기대한 100이 아닐 수 있는 이유와 금액에 대한 대안을 설명해 보세요.

잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?

답변과 점검 포인트 펼치기답변 접기
01

구두 답변

정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.

0.1은 십진수로는 간단하지만 이진 부동소수점에서는 유한한 비트로 정확히 표현되지 않을 수 있습니다. 저장된 근삿값을 다시 더할 때 작은 오차가 누적되어 내부 결과가 수학적 100과 달라질 수 있고, formatter가 이를 100으로 보이게 만들 수도 있습니다. 출력 문자열만 보고 정확하다고 판단하면 안 됩니다.

금액이라면 목적에 따라 exact decimal 또는 minor unit 정수를 선택하겠습니다. cents가 고정된 통화라면 0.10달러를 10으로 저장해 천 번 더한 뒤 1000 cents로 바꾸는 방식이 단순합니다. 다만 세율·환율처럼 분수가 필요한 계산은 중간 decimal scale과 반올림 경계를 따로 둬야 합니다. PostgreSQL numeric/decimal은 정확한 정밀도를 선택할 수 있는 타입이지만 overflow와 도메인 반올림까지 자동 해결하지는 않습니다.

반대로 물리량처럼 작은 오차를 허용하고 넓은 범위나 빠른 부동 연산이 중요한 경우에는 float가 적합할 수 있습니다. 금액 비교에 임의 epsilon을 넣는 방식은 원장 동일성 계약을 대신하지 못합니다. 같은 입력을 decimal, minor unit, float로 계산해 내부값·게시값·누적 오차를 테스트 데이터로 비교하겠습니다.

실제 내부 상태를 확인하려면 출력 자릿수를 늘리고 엄격 비교를 함께 봅니다. double로 0.1을 1000회 누적하는 작은 검산은 99.9999999999986 부근이며 sum === 100은 false가 될 수 있습니다. 반면 formatter가 두 자리로 바꾸면 100.00이므로 화면값과 저장값을 혼동하면 안 됩니다. 합산 순서도 중요합니다. binary32에서 [1e8, 1, -1e8]는 첫 덧셈에서 1이 사라져 0이 될 수 있지만 [1e8, -1e8, 1]은 1이 남습니다. 이는 float가 항상 쓸모없다는 뜻이 아니라 오차 허용·순서·누적 알고리즘을 계약해야 한다는 뜻입니다.

금액의 cents가 고정이면 정수 10을 천 번 더해 10000 cents로 만드는 경로가 가장 설명하기 쉽습니다. 환율처럼 중간 분수가 필요한 경우 exact decimal로 계산하고 통화별 게시 scale에서 한 번 확정합니다. epsilon을 임의로 정해 equality를 통과시키면 서로 다른 원장 금액을 같게 만들 수 있으므로 법적 금액 비교의 대안이 되지 않습니다.

02

득점 포인트

이해가 드러나는 지점을 확인해 보세요.

  • 0.1의 이진 표현 불가능성과 누적 오차를 연결합니다.
  • 출력 반올림과 내부 표현을 구분합니다.
  • fixed minor unit와 decimal 중간 계산을 목적별로 선택합니다.
  • float의 epsilon과 금액 원장 정확성을 구분합니다.
03

감점 포인트

놓치기 쉬운 조건과 오해를 짚어 보세요.

  • 모든 부동소수점 계산이 항상 눈에 보이게 틀린다고 합니다.
  • decimal이면 overflow·반올림 정책까지 자동 해결된다고 합니다.
  • 화면에 100으로 표시된 것을 내부 합계의 정확한 증거로 삼습니다.
04

더 파고들 거리

하나 더 질문하며 이해의 범위를 넓혀 보세요.

  • JavaScript Number로 큰 금액·ID를 함께 다룰 때 어떤 표현을 사용하겠습니까?
  • 환율 계산 후 각 통화의 scale을 어떻게 보존하고 게시하겠습니까?

득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.

← 전체 질문 보기