아이템 60. 정확한 답이 필요하면 float와 double 은 피하라

이펙티브 자바

아이템 60. 정확한 답이 필요하면 float와 double 은 피하라

개발을 할때 floating point 문제에 직면하게 되는데 그 내용에 대해서 푸는 문제이다.

먼저 아래 코드를 보면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package com.github.sejoung.codetest.general;

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);
}
}


실행결과

1
2
3
4
3개 구입
잔돈(달러): 0.3999999999999999

Process finished with exit code 0

위에 결과가 전혀 다르게 나오게 된다

float와 double금융타입의 계산과는 맞지 않다.

그럼 대안으로는 int나 long, BigDecimal을 사용해야 된다

아래 코드는 int를 사용한 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.github.sejoung.codetest.general;

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
2
3
4
5

4개 구입
잔돈(센트): 0

Process finished with exit code 0

위에서는 정수로서 문제를 풀었고 소수점까지 계산 해야 되면 BigDecimal을 사용해야 되는데
단점이 2가지 있다.

  • 기본타입 보다 사용하기 불편하다.

  • 무겁고 느리다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

package com.github.sejoung.codetest.general;

import java.math.BigDecimal;

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);
}
}


실행결과

1
2
3
4
5

4개 구입
잔돈(달러): 0.00

Process finished with exit code 0

참조