Open
Description
Discussed in https://github.com/orgs/Study-2-Effective-Java/discussions/145
Originally posted by bunsung92 March 7, 2023
📝 구성
Table of contents generated with markdown-toc
0. TL;DR 🔨
- 소수점의 정확한 연산을 위함이라면 float과 double을
지양
하라. - BigDecimal의
반올림 모드
는 정확한 연산을 돕는다. - 성능 향상과 소수점 직접 추적이 가능하다면 int와 long을 사용하라.
1. 금융 계산에 부동소수 타입의 사용
�float과 double은 부동소수를 사용한다.
금융계산처럼 명확해야 하는 계산에는 지양해야한다.
아래와 같은 코드가 있다.
- 금융 계산에 부동소수 타입을 사용
private static void floatingCalculate() {
double funds = 1.00;
int itemBought = 0;
for (double price = 0.10; funds >= price; price += 0.10) {
funds -= price;
itemBought++;
}
System.out.println(itemBought + "개 구입");
System.out.println("잔돈(달러) : " + funds);
}
기대한 결과는 사탕 1개 -> 사탕 2개 -> 사탕 3개 -> 사탕 4개 의 구매를 통해 1 + 2 + 3 + 4의 결과로 1달러의 소비를 원했다.
좀 더 계산이 명확해야한다.
2. BigDecimal을 사용한 해법
private static void bigDecimalCalculate() {
final BigDecimal TEN_CENTS = new BigDecimal(".10");
int itemBought = 0;
BigDecimal funds = new BigDecimal(1.00);
for (BigDecimal price = TEN_CENTS; funds.compareTo(price) >= 0; price = price.add(TEN_CENTS)) {
funds = funds.subtract(price);
itemBought++;
}
System.out.println(itemBought + "개 구입");
System.out.println("잔돈(달러) : " + funds);
}
부동소수점의 사용과 달리 명확한 계산결과가 반환된다.
하지만 BigDecimal은 두가지 단점이 있다.
- 불편하다.
- 느리다.
이를 대안할 수 있는 방법이 있는데...
3. 정수 타입을 사용한 해법
위의 식을 다시 생각 해보면 다룰 수 있는 값의 크기가 제한할 수있다. (꼭 소수점을 사용하지 않아도 계산이 된다.)
즉 아래와 같은 코드로 작성이 가능하다.
private static void integerCalculate() {
int itemBought = 0;
int funds = 100;
for (int price = 10; funds >= price; price += 10) {
funds -= price;
itemBought++;
}
System.out.println(itemBought + "개 구입");
System.out.println("잔돈(센트) : " + funds);
}
4. 핵심 요약 📚
- 위의 예제는 각각의 상황에 알맞게 사용 해야한다.
- 정확한 소수점이 필요한 계산이라면 반드시 BigDecimal을 사용해야한다.
- 3번의 예제는 소수점 계산이 필요하지 않은 계산인지를 한번 더 체크하자는 의미에서 작성된 것 같다.
int는 아홉 자리 십진수
long 열여덟 자리 십진수
열여덟 자리 십진수 이상은 BigDecimal 사용
5. 회고 🧹
2023.03.19 일
- 코테 하다보면 소수점 계산에서 생각보다 화를 입기 쉽상이다. 그리고 어쩔때는 double 정도로 해결되는 문제들도 많았지만
- 공간 복잡도, 시간 복잡도에 크게 구애받지 않는다면 BigDecimald을 사용해 해결해 볼 수 있도록 해야겠다.