
자바에서 소수(실수)를 표현할 때는 보통 float이나 double을 사용합니다.
하지만 강의나 실무에서 이런 말을 자주 듣게 됩니다.
double과 float 대신 BigDecimal을 사용하세요!
이 말은 단순한 습관이나 규칙이 아니라, 부동소수점 연산의 정확도 문제라는 기술적인 이유가 있습니다.
오늘은 다음과 같은 내용을 함께 알아볼게요.
- float, double에서 오차가 발생하는 이유
- 부동소수점 표현 방식(IEEE 754 표준)의 한계
- BigDecimal이 이러한 문제를 어떻게 해결하는지
- 각 자료형을 언제, 어떻게 사용해야 하는지
부동소수점 연산의 정확도 문제
다음은 간단한 예제입니다.
double a = 1.03;
double b = 0.42;
System.out.println(a - b);
예상 결과는 0.61이지만, 실제 출력값은 다음과 같습니다.
0.6100000000000001
왜 이런 일이 생길까요? 이것이 바로 부동소수점 연산의 대표적인 한계입니다.
자바의 float과 double은 2진수 기반의 부동소수점 방식(IEEE 754 표준)을 사용합니다.
문제는, 10진수로 정확히 표현되는 값이 2진수로는 무한소수가 되는 경우가 많다는 점입니다.
예를 들어 0.1이나 0.42 같은 수는 2진수로 완벽히 표현할 수 없습니다.
따라서 컴퓨터는 이 값을 가장 근사한 이진수 형태로 저장하게 되고, 그 결과 미세한 오차가 발생합니다.
부동소수점이란 무엇인가?
컴퓨터는 모든 데이터를 0과 1(이진수)로 저장합니다.
하지만 10진수의 소수 중에는 이진수로 정확하게 표현할 수 없는 값이 있습니다.
그 대표적인 예가 바로 0.1입니다.
0.1(10진수) = 0.000110011001100110011...(2진수, 무한 반복)
이처럼 이진수로 끝없이 반복되는 형태는 컴퓨터가 전부 저장할 수 없기 때문에,
일정한 자리까지만 저장하고 나머지는 잘라내어 근삿값(approximation)으로 처리합니다.
이러한 실수 표현 방식은 국제 표준인 IEEE 754를 따르며,
실수를 다음 세 가지 구성 요소로 나누어 저장합니다.
| 구성 요소 | 의미 |
| Sign(부호) | 양수인지 음수인지 표시 |
| Exponent(지수) | 수의 크기를 조정 |
| Fraction(가수) | 소수점 이하의 정밀도 표현 |
가수(Fraction) 부분의 비트 수에는 한계가 있기 때문에,
무한히 반복되는 소수는 정확히 저장할 수 없습니다.
결과적으로 저장된 값은 실제 값의 근삿값이 되며,
연산을 반복할수록 이러한 미세한 오차가 누적되어 눈에 띄는 차이로 나타날 수 있습니다.
왜 BigDecimal이 필요한가?
앞서 살펴본 것처럼, float과 double은 부동소수점 방식의 한계 때문에 미세한 오차가 발생할 수 있습니다.
이 문제를 해결하기 위해 자바는 BigDecimal 클래스를 제공합니다.
BigDecimal은 부동소수점이 아닌, 유효숫자와 소수점의 위치를 기준으로 수를 표현합니다.
즉, 정확한 십진수 연산을 지원하는 클래스입니다.
💡 예시로 비교해보기
BigDecimal a = new BigDecimal("1.03");
BigDecimal b = new BigDecimal("0.42");
System.out.println(a.subtract(b));
출력 결과는 다음과 같습니다.
0.61
이처럼
BigDecimal을 사용하면 부동소수점의 근사 표현으로 인한 오차가 발생하지 않습니다.
🔍 BigDecimal의 내부 구조
BigDecimal은 수를 다음 두 가지 요소로 나누어 저장합니다.
| 구성 요소 | 역할 |
| BigInteger | 실제 숫자를 정수 형태로 저장 (예: 103, 42) |
| Scale | 소수점의 위치를 저장 (예: 소수 둘째 자리까지) |
즉, 1.03은 내부적으로 "103"이라는 정수 값과 소수점 둘째 자리(scale=2)로 관리됩니다.
이 방식 덕분에 무한소수나 반복소수도 정밀하게 표현할 수 있으며,
금융 계산처럼 정확도가 중요한 상황에서 특히 유용합니다.
Double / Float vs BigDecimal 비교
| 구분 | double / float |
BigDecimal |
| 표현 방식 | IEEE 754 부동소수점 | 정밀도 기반(유효숫자 + 스케일) |
| 정확도 | 근삿값 → 오차 발생 가능 | 완전한 소수 표현 가능 |
| 속도 | 빠름 | 느림 (객체 연산) |
| 메모리 사용 | 적음 | 많음 |
| 사용 예 | 물리 계산, 그래픽 처리 등 | 금전 계산, 정밀도가 필요한 로직 등 |
그렇다면 double과 float은 버려야 할까?

결론부터 말하면, 아니요.double과 float을 완전히 대체할 필요는 없습니다.
BigDecimal은 정확도는 높지만 연산 속도가 느리고 메모리 사용량이 많습니다.
반면 double과 float은 빠르지만, 부동소수점 특성상 오차가 누적될 수 있습니다.
따라서 정확도와 성능 중 어떤 것이 더 중요한지에 따라 선택해야 합니다.
정확도가 중요하다면 → BigDecimal
속도가 중요하다면 → double / float
정확도와 성능의 균형 잡기
float과 double은 빠르고 효율적인 자료형이지만,
부동소수점 오차라는 근본적인 한계를 가지고 있습니다.
이에 비해 BigDecimal은 이러한 문제를 해결하기 위해 만들어진 정확도 중심의 대안입니다.
특히 금융, 회계, 과학 계산처럼 정밀도가 절대적으로 중요한 분야에서는 반드시 사용해야 합니다.
결국 핵심은 정확도와 성능 사이의 균형을 이해하고,
상황에 맞는 자료형을 선택하는 능력입니다.
이러한 능력을 길러 좋은 소프트웨어를 만들어나가는 개발자가 되도록 더욱 노력해야겠습니다! 💪
'Language > Java ☕️' 카테고리의 다른 글
| Java static 키워드 완전 가이드 (0) | 2024.05.22 |
|---|---|
| 자바 메모리 구조 이해하기 (0) | 2024.05.22 |
| 자바의 가비지 컬렉션(GC) 한 번에 이해하기 (0) | 2024.02.02 |
| String vs StringBuffer vs StringBuilder — 자바 문자열 클래스의 차이 완전 정리 (0) | 2024.02.02 |
| JDK, JRE, JVM의 차이와 자바 실행 구조 이해하기 (0) | 2024.02.01 |
안녕하세요, 저는 주니어 개발자 박석희 입니다. 언제든 하단 연락처로 연락주세요 😆