티스토리 뷰
728x90
반응형
BigDecimal은 Java에서 정밀한 소수 계산이 필요할 때 사용하는 클래스
float나 double 타입은 부동소수점 오차가 있어서 정확한 소수 계산이 필요할 때는 적합하지 않다.
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal num1 = new BigDecimal("10.25");
BigDecimal num2 = new BigDecimal("3.1");
// 덧셈
BigDecimal sum = num1.add(num2);
// 나눗셈 (소수점 자릿수 지정 필요)
BigDecimal result = num1.divide(num2, 10, BigDecimal.ROUND_HALF_UP); // 소수점 10자리까지 반올림
System.out.println("합: " + sum); // 13.35
System.out.println("나눗셈: " + result); // 3.3064516129
}
}
주요 메서드
add() | 덧셈 |
subtract() | 뺄셈 |
multiply() | 곱셈 |
divide() | 나눗셈 (반드시 소수 자릿수 설정) |
setScale() | 소수점 자리수 지정 |
compareTo() | 크기 비교 (-1, 0, 1 리턴) |
equals() | 정확한 값 비교 |
반올림 모드
- new BigDecimal(숫자)는 부동소수점 오차가 생길 수 있으므로
👉 반드시 문자열로 생성하는 게 좋아요: new BigDecimal("1.1") - 나눗셈할 때는 소수 자릿수(scale) 와 반올림 방식(rounding mode) 지정 안 하면 ArithmeticException 발생
ROUND_UP | 무조건 올림 |
ROUND_DOWN | 무조건 버림 |
ROUND_HALF_UP | 5 이상이면 올림 (일반적인 반올림) |
ROUND_HALF_EVEN | 오사오입 반올림 |
float와 double에서 부동소수점 오차가 생기는 이유
- 컴퓨터가 10진 소수를 정확하게 2진수로 표현하지 못하기 때문
- 10진수 소수는, 대부분 컴퓨터의 2진수로는 무한 반복 소수
- 컴퓨터는 메모리의 한계 때문에 이걸 일정 비트 수로 잘라서 저장
- 근사값만 저장되기 때문에 오차가 발생
0.1(10진수) = 0.000110011001100... (2진수, 무한 반복)
타입크기정밀도(소수점 자리)
float | 32비트 | 약 7자리 정밀도 |
double | 64비트 | 약 15~16자리 정밀도 |
public class Main {
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;
double sum = a + b;
System.out.println("0.1 + 0.2 = " + sum);
//0.1 + 0.2 = 0.30000000000000004
}
}
BigDecimal이 부동소수점 오차를 피할 수 있는 이유
- 이진법 대신 십진법(10진수)을 기반으로 수를 처리하기 때문
- BigDecimal 내부에서는 숫자를 다음처럼 문자열처럼 분해해서 저장
- 이 방식은 정확한 소수값을 표현하고 계산할 수 있게 해줘요.
이진 부동소수점처럼 무한 반복 표현이 필요 없고, 자리수도 원하는 만큼 지정할 수 있기 때문
BigDecimal value = new BigDecimal("123.456");
BigDecimal b1 = new BigDecimal("0.1");
BigDecimal b2 = new BigDecimal("0.2");
BigDecimal result = b1.add(b2);
System.out.println(result); // 0.3
내부적으로는 다음처럼 저장:
정수부: 123456
소수 자릿수(scale): 3 (소수점이 3자리 뒤에 있다는 의미)
즉, 실제 숫자는 (정수부) × 10^(-scale)
→ 123456 × 10^(-3) = 123.456
10진 소수를 2진수 소수로 바꾸는 방법
소수부는 다음 과정을 반복해서 변환합니다:
- 10진 소수 × 2
- 정수부(0 또는 1)를 기록
- 소수부만 남겨서 다시 ×2
- 원하는 정밀도까지 반복
1) 0.1 × 2 = 0.2 → 0
2) 0.2 × 2 = 0.4 → 0
3) 0.4 × 2 = 0.8 → 0
4) 0.8 × 2 = 1.6 → 1
5) 0.6 × 2 = 1.2 → 1
6) 0.2 × 2 = 0.4 → 0
7) 0.4 × 2 = 0.8 → 0
8) 0.8 × 2 = 1.6 → 1
9) 0.6 × 2 = 1.2 → 1
10) 0.2 × 2 = 0.4 → 0
...
- 0.1은 2진수로 정확하게 표현 불가능한 무한 반복 소수
- 그래서 float나 double 같은 2진수 기반 타입으로 표현하면 근사값만 저장됨
10진수2진수 표현정확한 표현 가능 여부
0.5 | 0.1 | 가능 |
0.25 | 0.01 | 가능 |
0.1 | 0.000110011... | 불가능 (무한 반복) |
0.2 | 0.00110011... | 불가능 |
728x90
반응형
'Java' 카테고리의 다른 글
[Java] Jackson Streaming API, TreeModel (0) | 2025.04.19 |
---|---|
[Java] BigInteger (0) | 2025.04.19 |
[Java] DIP (Dependency Inversion Principle) (0) | 2025.03.03 |
[Java] Bounded WildCard (1) | 2025.03.03 |
[Java] Generic (0) | 2025.03.03 |
반응형
300x250