💥 개요
float과 double은 과학과 공학 계산용으로 설계됐다. 이진 부동소수점 연산에 쓰이며, 넓은 범위의 수를 정밀한 '근사치'로 계산하도록 설계됐다.
정확한 결과가 필요하면 사용하면 안되며, 특히 금융 관련 계산과 맞지않는다.
1.03 - 0.42 는 출력시 0.6100000000000001을 출력한다. 이건 특수한 사례도 아니다.
⚠️ 금융 계산에 잘못된 예시
public class Change {
// 코드 60-1 오류 발생! 금융 계산에 부동소수 타입을 사용했다. (356쪽)
public static void main(String[] args) {
double funds = 1.00;
int itemsBought = 0;
for (double price = 0.10; funds >= price; price += 0.10) {
funds -= price;
itemsBought++;
}
System.out.println(itemsBought + "개 구입");
System.out.println("잔돈(달러): " + funds);
}
}
이 코드에서 사탕을 계산시 아래와 같이 생각과는 다른 결과가 나온다. 아주 작지만 미세하게 차이가 발생한 것이다.
❤️ 금융 계산시 올바른 예시
public class BigDecimalChange {
// 코드 60-2 BigDecimal을 사용한 해법. 속도가 느리고 쓰기 불편하다. (356쪽)
public static void main(String[] args) {
final BigDecimal TEN_CENTS = new BigDecimal(".10");
int itemsBought = 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);
itemsBought++;
}
System.out.println(itemsBought + "개 구입");
System.out.println("잔돈(달러): " + funds);
}
}
위 코드는 무겁고 속도도 느리며 사용하기에도 불편하다. 하지만 아래와 같이 정확하게 잔돈이 0달러가 남는다.
단발성 계산은 상관 없겠지만, 사용하기 불편한 것은 조금 아쉽다.
❓ BigDecimal의 대안
대안으로 int 혹은 long 타입을 쓸 수도 있다. 다만 그런 경우 다룰 수 있는 값의 크기가 제한되고, 소수점을 직접 관리해야 한다. 아래 예시에서는 모든 계산을 달러 대신 센트로 수행하여 이 문제를 해결했다.
public class IntChange {
// 코드 60-3 정수 타입을 사용한 해법 (357쪽)
public static void main(String[] args) {
int itemsBought = 0;
int funds = 100;
for (int price = 10; funds >= price; price += 10) {
funds -= price;
itemsBought++;
}
System.out.println(itemsBought + "개 구입");
System.out.println("잔돈(센트): " + funds);
}
}
🔎 더 알아보기
1.BigDecimal 사용법
특이하지만 double 타입보다는 String 타입으로 BigDecimal을 사용하는걸 권장하고 있다.
public static void main(String[] args) {
BigDecimal bigDecimalString = new BigDecimal("10000.12345");
System.out.println(bigDecimalString); //10000.12345
BigDecimal bigDecimalDouble = new BigDecimal(10000.12345);
System.out.println(bigDecimalDouble); //10000.123449999999138526618480682373046875
}
그 이유는 위와 같이 정확한 값을 도출해낼 수 없기 때문이다.
2.사칙 연산자 사용불가
[refference]
Effective java 3E
'Study > 이펙티브 자바' 카테고리의 다른 글
[Effective Java] 객체는 인터페이스를 사용해 참조하라 (0) | 2024.04.22 |
---|---|
[Effective Java] 반환 타입으로는 스트림보다 컬렉션이 낫다 (0) | 2024.04.20 |
[Effective Java] 공개된 API 요소에는 항상 문서화 주석을 작성하라 (0) | 2024.03.18 |
[Effective Java] 스트림 병렬화는 주의해서 적용하라 (0) | 2024.02.21 |