ArithmeticException :“비 종료 소수점 확장; 정확하게 표현할 수있는 소수 결과가 없습니다”


507

다음 코드가 아래에 표시된 예외를 발생시키는 이유는 무엇입니까?

BigDecimal a = new BigDecimal("1.6");
BigDecimal b = new BigDecimal("9.2");
a.divide(b) // results in the following exception.

예외:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

답변:


843

로부터 자바 (11) BigDecimal워드 프로세서 :

MathContext개체 10-0의 정밀도가 설정된 공급 (예 MathContext.UNLIMITED), 연산은 더 취하지 연산 방법이며, 정확한있는 MathContext개체. (이것은 5 이전 릴리스에서 지원 된 유일한 동작입니다.)

정확한 결과를 계산 한 결과, MathContext정밀도 설정이 0 인 객체 의 반올림 모드 설정은 사용되지 않으므로 관련이 없습니다. 나누기의 경우 정확한 몫은 무한 길이의 십진수 확장을 가질 수 있습니다. 예를 들어 1을 3으로 나눈 값입니다.

몫에 끝나지 않는 10 진수 확장이 있고 정확한 결과를 반환하도록 연산이 지정된 경우 ArithmeticException가 발생합니다. 그렇지 않으면 다른 작업에서와 같이 정확한 분할 결과가 반환됩니다.

수정하려면 다음과 같이해야합니다 .

a.divide(b, 2, RoundingMode.HALF_UP)

여기서 2는 스케일이고 RoundingMode.HALF_UP은 반올림 모드입니다.

자세한 내용은 이 블로그 게시물을 참조하십시오 .


3
이것은 재스퍼 오류에도 적용됩니다. community.jaspersoft.com/questions/528968/…
shareef

27
2는 아닙니다 precision. 그것은이다 scale. docs.oracle.com/javase/7/docs/api/java/math/…를
John Manko

(new BigDecimal (100)). divide (new BigDecimal (0.90), 2, RoundingMode.HALF_UP)
egemen

@AnandVarkeyPhilips 그것은 규모입니다. Javadoc을 참조하십시오 . 수정이 거부되었습니다.
Lorne의 후작

@ user207421, 실수로 편집하여 되돌리기를 시도했습니다. 그러나 편집을 삭제할 충분한 포인트가 없었습니다 .... meta.stackexchange.com/questions/80933/…
Anand Varkey Philips

76

정밀도와 반올림 모드를 지정하지 않기 때문입니다. BigDecimal은 10, 20, 5000 또는 무한 소수점 자리를 사용할 수 있으며 여전히 숫자를 정확하게 표현할 수는 없다고 불평합니다. 따라서 잘못된 BigDecimal을 제공하는 대신 사용자에게 윙윙 거리는 소리입니다.

그러나 RoundingMode와 정밀도를 제공하면 (예 : 1.333333333에서 무한대를 1.3333과 같은 것으로 변환 할 수 있지만 ... 프로그래머는 당신이 어떤 정밀도에 만족하는지 말할 필요가 있습니다 '.



13

이러한 문제를 해결하기 위해 아래 코드를 사용했습니다.

a.divide(b, 2, RoundingMode.HALF_EVEN)

2는 정밀도입니다. 이제 문제가 해결되었습니다.


3
코드 외에도 몇 가지 설명이 제공되어야합니다.
Martin Serrano

11
2는 아닙니다 precision. 그것은이다 scale. docs.oracle.com/javase/7/docs/api/java/math/…
John Manko

3
금융 애플리케이션에는 RoundingMode.HALF_EVEN이 권장됩니다. 이것은 은행업에서 사용되는 것입니다
ACV

John Mankos의 정확성에 대한 의견이 혼란 스러우신 분들은이 답변을 참조하십시오 stackoverflow.com/questions/4591206/…
Stimpson Cat

5

내 코드 줄이 다음과 같기 때문에 동일한 문제가 발생했습니다.

txtTotalInvoice.setText(var1.divide(var2).doubleValue() + "");

십진수 정밀도를 쓰지 않았기 때문에 이전 답변을 읽는 것으로 변경합니다.

txtTotalInvoice.setText(var1.divide(var2,4, RoundingMode.HALF_UP).doubleValue() + "");

4는 10 진법

AND RoundingMode는 Enum 상수이며,이 중 하나를 선택할 수 있습니다 UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

이 경우 HALF_UP의 결과는 다음과 같습니다.

2.4 = 2   
2.5 = 3   
2.7 = 3

RoundingMode여기 에서 정보 를 확인할 수 있습니다 : http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/


4는 정밀도가 아닌 척도입니다.
Lorne의 후작

3

결과를 반올림하는 문제는 나를위한 해결책은 다음과 같습니다.

divider.divide(dividend,RoundingMode.HALF_UP);

1

BigDecimal에 대한 답변에서 ArithmeticException이 발생 함

public static void main(String[] args) {
        int age = 30;
        BigDecimal retireMentFund = new BigDecimal("10000.00");
        retireMentFund.setScale(2,BigDecimal.ROUND_HALF_UP);
        BigDecimal yearsInRetirement = new BigDecimal("20.00");
        String name = " Dennis";
        for ( int i = age; i <=65; i++){
            recalculate(retireMentFund,new BigDecimal("0.10"));
        }
        BigDecimal monthlyPension =   retireMentFund.divide(
                yearsInRetirement.divide(new BigDecimal("12"), new MathContext(2, RoundingMode.CEILING)), new MathContext(2, RoundingMode.CEILING));      
        System.out.println(name+ " will have £" + monthlyPension +" per month for retirement");
    }
public static void recalculate (BigDecimal fundAmount, BigDecimal rate){
        fundAmount.multiply(rate.add(new BigDecimal("1.00")));
    }

나누기 메소드 호출에 MathContext 객체를 추가하고 정밀도 및 반올림 모드를 조정하십시오. 문제를 해결해야합니다


0

프로그램은 십진수의 정밀도를 알지 못하므로 다음을 throw합니다.

java.lang.ArithmeticException: Non-terminating decimal expansion

예외를 우회하는 솔루션 :

MathContext precision = new MathContext(int setPrecisionYouWant); // example 2
BigDecimal a = new BigDecimal("1.6",precision);
BigDecimal b = new BigDecimal("9.2",precision);
a.divide(b) // result = 0.17
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.