[교재 EffectiveJava] 아이템 60. 정확한 답이 필요하다면 float와 double은 피하라

반응형
728x90
반응형

float와 double 타입의 단점

float 와 double 타입은 과학과 공학 계산용으로 설계되었다. 이는 정확한 결과가 필요할 때는 사용하면 안된다. float와 double 타입은 특히 금융 관련 계산과는 맞지 않는다. 0.1 혹은 10의 음의 거듭제곱수 등을 표현할 수 없기 때문이다.

 

오류 발생하는 코드
package com.java.effective.item60;

public class Main {
    public static void main(String[] args) {
        double funds = 1.00;
        int itemBought = 0;
        
        for (double price = 0.10; funds >= price; price += 0.10) {
            funds = funds - price;
            itemBought++;
        }

        System.out.println(itemBought + "개 구입");
        System.out.println("잔돈(달러):" + funds);
    }
}

금융 계산에 부동소수 타입을 사용했다. 이는 결과가 아래와 같다.

 

결과
3개 구입
잔돈(달러):0.3999999999999999

이는 잘못된 결과다. 이 문제를 올바로 해결하려면, BigDecimal, int 혹은 long을 사용해야한다. 

 

 

BigDecimal 사용으로 변경

BigDecimal 로 변경
package com.java.effective.item60;

import java.math.BigDecimal;

public class Main2 {
    public static void main(String[] args) {
        final BigDecimal TEN_CNETS = new BigDecimal("0.10");

        int itemsBought = 0;
        BigDecimal funds = new BigDecimal("1.00");

        for (BigDecimal price = TEN_CNETS;
            funds.compareTo(price) >= 0; price = price.add(TEN_CNETS)) {
            funds = funds.subtract(price);
            itemsBought++;
        }

        System.out.println(itemsBought + "개 구입");
        System.out.println("잔돈(달러): " + funds);
    }
}

위 코드는 아래 결과와 같이 올바른 답이 나온다.

 

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

 

 

BigDecimal의 단점

기본 타입보다 훨씬 쓰기 불편하고, 훨씬 느리다. BigDecimal의 대안으로 int 혹은 long 타입을 쓸 수도 있다.  그럴 경우 다룰 수 있는 값의 크기가 제한되고, 소수점을 직접 관리해야 한다. 이번 예시는 달러 대신 센트로 수행하면 훨씬 빠르고 편리하게 구현할 수 있다.

 

int 타입
package com.java.effective.item60;

import java.math.BigDecimal;

public class Main3 {
    public static void main(String[] args) {
        int itemsBought = 0;
        int funds = 100;

        for (int price = 10; funds >= price; price += 10) {
            funds = funds - price;
            itemsBought++;
        }

        System.out.println(itemsBought + "개 구입");
        System.out.println("잔돈(달러): " + funds);
    }
}

 

결과
4개 구입
잔돈(달러): 0

 

 

상황에서의 선택

1) int

숫자를 아홉자리 십진수로 표현할 수 있을 경우

 

2) long

열여덟 자리 십진수로 표현할 수 있을 경우

 

3) BigDecimal

열여덟 자리를 넘어가는 경우

 

 

 

반응형

Designed by JB FACTORY