Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Irisation23 opened this issue Mar 19, 2023 Discussed in #145 · 0 comments
Open
Assignees
Labels
9장 일반적인 프로그래밍 원칙 이펙티브 자바 9장 (일반적인 프로그래밍 원칙)

Comments

@Irisation23
Copy link
Member

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을 사용해 해결해 볼 수 있도록 해야겠다.
@Irisation23 Irisation23 added the 9장 일반적인 프로그래밍 원칙 이펙티브 자바 9장 (일반적인 프로그래밍 원칙) label Mar 19, 2023
@Irisation23 Irisation23 self-assigned this Mar 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
9장 일반적인 프로그래밍 원칙 이펙티브 자바 9장 (일반적인 프로그래밍 원칙)
Projects
None yet
Development

No branches or pull requests

1 participant