[예시]
주머니에 1.03달러가 있었는데 그중 42센트를 썼다고 해보자.
- System.out.println(1.03 - 0.42);
- 안타깝게도 이 코드는 0.6100000000000001을 출력한다.
주머니에 1달러가 있었는데 10센트짜리 사탕 9개를 샀다고 해보자.
- System.out.println(1.00 - 9 * 0.10);
- 이 코드는 0.09999999999999998을 출력한다.
주머니에는 1달러가 있고, 선반에 10센트, 20센트, 30센트, ... 1달러짜리의 맛있는 사탕이 놓여 있다고 해보자.
- 10센트짜리부터 하나씩, 살 수 있을 때까지 사보자. 사탕을 몇 개나 살 수 있고, 잔돈은 얼마가 남을까?
- 결과값을 출력하기 전에 반올림하면 해결되리라 생각할지 모르지만, 반올림을 해도 틀린 답이 나올 수 있다.
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);
}
- 사탕 3개를 구입한 후 잔돈은 0.3999999999999999달러가 남았다.
[Why]
float와 double 타입은 과학과 공학 계산용으로 설계되었다.
- 이진 부동소수점 연산에 쓰이며, 넓은 범위의 수를 빠르게 정밀한 '근사치'로 계산하도록 세심하게 설계되었다.
- 따라서 정확한 결과가 필요할 때는 사용하면 안 된다.
[When]
float와 double 타입은 특히 금융 관련 계산과는 맞지 않는다.
- 0.1 혹은 10의 음의 거듭제곱 수(10^-1, 10^-2 등)를 표현할 수 없기 때문이다.
[How]
금융 계산에는 BigDecimal, int 혹은 long을 사용해야 한다.
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);
}
- BigDecimal에는 단점이 두 가지 있다.
- 기본 타입보다 쓰기가 훨씬 불편하고, 훨씬 느리다.
BigDecimal의 대안으로 int 혹은 long 타입을 쓸 수도 있다.
- 다룰 수 있는 값의 크기가 제한되고, 소수점을 직접 관리해야 한다.
- 이번 예에서는 모든 계산을 달러 대신 센트로 수행하면 이 문제가 해결된다.
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);
}
'독서찰기(讀書札記) > 이펙티브 자바' 카테고리의 다른 글
[아이템 62] 다른 타입이 적절하다면 문자열 사용을 피하라 (0) | 2022.03.27 |
---|---|
[아이템 61] 박싱된 기본 타입보다는 기본 타입을 사용하라 (0) | 2022.03.26 |
[아이템 59] 라이브러리를 익히고 사용하라 (0) | 2022.03.25 |
[아이템 58] 전통적인 for 문보다는 for-each 문을 사용하라 (0) | 2022.03.24 |
[아이템 57] 지역변수의 범위를 최소화하라 (0) | 2022.03.24 |