Skip to content

아이템 60. 정확한 답이 필요하다면 float와 double은 피하라 - Fin #162

Open
@Irisation23

Description

@Irisation23

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달러의 소비를 원했다.

하지만 실제 결과는
image

좀 더 계산이 명확해야한다.

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

image

부동소수점의 사용과 달리 명확한 계산결과가 반환된다.
하지만 BigDecimal은 두가지 단점이 있다.

  1. 불편하다.
  2. 느리다.

이를 대안할 수 있는 방법이 있는데...

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

결과는 아래와 같다.
image

4. 핵심 요약 📚

  • 위의 예제는 각각의 상황에 알맞게 사용 해야한다.
  • 정확한 소수점이 필요한 계산이라면 반드시 BigDecimal을 사용해야한다.
  • 3번의 예제는 소수점 계산이 필요하지 않은 계산인지를 한번 더 체크하자는 의미에서 작성된 것 같다.

int는 아홉 자리 십진수
long 열여덟 자리 십진수
열여덟 자리 십진수 이상은 BigDecimal 사용

5. 회고 🧹

2023.03.19 일

  • 코테 하다보면 소수점 계산에서 생각보다 화를 입기 쉽상이다. 그리고 어쩔때는 double 정도로 해결되는 문제들도 많았지만
  • 공간 복잡도, 시간 복잡도에 크게 구애받지 않는다면 BigDecimald을 사용해 해결해 볼 수 있도록 해야겠다.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions