ArithmeticException:「終了しない10進数の展開。正確に表現できる10進数の結果はありません」


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

以下からのJavaの11 BigDecimalのドキュメント

MathContextオブジェクトに精度設定0が指定されている場合(たとえば、MathContext.UNLIMITED)、MathContextオブジェクトを取らない算術メソッドと同様に、算術演算は正確です。(これは、5より前のリリースでサポートされていた唯一の動作です。)

正確な結果の計算の結果として、MathContext精度設定が0のオブジェクトの丸めモード設定は使用されないため、無関係です。除算の場合、正確な商は無限に長い10進展開を持つことができます。たとえば、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。それはですscaledocs.oracle.com/javase/7/docs/api/java/math/…を
John

(new BigDecimal(100))。divide(new BigDecimal(0.90)、2、RoundingMode.HALF_UP)
egemen 2018年

@AnandVarkeyPhilipsスケールです。Javadocを参照してください。拒否された編集。
ローン侯爵

@ user207421、私は誤って....それを編集したと復帰しようとした..しかし、編集、削除するための十分なポイントを持っていませんでしmeta.stackexchange.com/questions/80933/...
アナンドVarkeyフィリップスは、

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。それはですscaledocs.oracle.com/javase/7/docs/api/java/math/…を
John

3
RoundingMode.HALF_EVENは、金融アプリケーションに推奨されます。これは銀行で使用されているものです
ACV '19

精度のジョン・Mankosさんのコメントで混乱している者については、この回答を参照してくださいstackoverflow.com/questions/4591206/...
Stimpson猫

5

私のコード行が次のとおりだったので、私はこれと同じ問題を抱えていました:

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

前の回答を読んで、これに変更します。これは、小数精度を記述していなかったためです。

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

4はDecimal Precison

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は精度ではなくスケールです。
ローン侯爵


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オブジェクトをdivideメソッド呼び出しに追加し、精度と丸めモードを調整します。これで問題が解決します


0

プログラムは、10進数が使用する精度を知らないため、以下をスローします。

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.