JavaScript의 숫자, 믿고 계신가요?

목차

  1. 🤔 문제의 시작: "어? 계산이 왜 안 맞지?"
  2. 🤷‍♂️ 왜 이런 문제가 생길까? (자바스크립트 부동소수점의 한계)
  3. 💡 해결책: decimal.js를 이용한 정확한 계산
  4. 💻 구현 코드: 안정성을 더하는 CurrencyCalculator 클래스
  5. 맺음말

🤔 문제의 시작: "어? 계산이 왜 안 맞지?"

프론트엔드 개발을 하다 보면 서버에서 받은 숫자 데이터를 단순히 더하거나 곱하는 경우가 많습니다. 특히 금액, 수량, 통계 등 정확성이 생명인 데이터를 다룰 때 JavaScript의 기본 숫자 타입(Number)을 무심코 사용하곤 합니다.

하지만 어느 날, 상상도 못 한 버그를 마주하게 됩니다.

0.1 + 0.2; 
// 결과: 0.30000000000000004

0.3 / 0.1; 
// 기대: 3 → 결과: 2.9999999999999996

0.1 + 0.7;
// 기대: 0.8 → 결과: 0.7999999999999999

0.1 * 0.1;
// 기대: 0.01 → 결과: 0.010000000000000002

(0.1 * 10 + 0.2 * 10) / 10;
// 결과: 0.3

분명 0.3이 나와야 할 계산이 미세하게 틀어지고, 이 작은 오차는 애플리케이션 전체에 치명적인 오류를 일으킬 수 있습니다. 고객의 돈을 다루는 커머스나 금융 서비스라면 더욱 심각한 문제겠죠.

이번 포스트에서는 이 문제의 원인을 파헤치고, decimal.js 라이브러리를 활용한 안정적인 해결책을 공유하고자 합니다.

( 실제로 금융관련 프로젝트의 프론트엔드 작업중 수치가 안맞아서 많이 혼란스러웠던 경험이 최근에 있었습니다 )


🤷‍♂️ 왜 이런 문제가 생길까? (자바스크립트 부동소수점의 한계)

부동소수점이란?

소수(실수)를 컴퓨터 메모리에 효율적으로 표현하고 계산하기 위한 방식입니다. 정수와 달리 소수는 자리수가 무한히 이어질 수 있어, 컴퓨터가 제한된 비트 수 안에 담기 위해 근사값으로 저장하게 됩니다.

JavaScript는 숫자를 IEEE 754 표준을 따르는 64비트 부동소수점(floating-point) 형식으로 저장합니다. 이 방식은 아주 큰 숫자나 작은 소수를 제한된 메모리 공간(64비트)에 효율적으로 표현하기 위해 '지수부'와 '가수부'로 나누어 저장하는 원리입니다.