ArithmeticException: “Ekspansi desimal tanpa-penghentian; tidak ada hasil desimal yang dapat diwakili secara pasti ”


507

Mengapa kode berikut memunculkan pengecualian di bawah ini?

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

Pengecualian:

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

Jawaban:


843

Dari Java 11 BigDecimaldocs :

Ketika suatu MathContextobjek diberikan dengan pengaturan presisi 0 (misalnya, MathContext.UNLIMITED), operasi aritmatika tepat, seperti halnya metode aritmatika yang tidak mengambil MathContextobjek. (Ini adalah satu-satunya perilaku yang didukung dalam rilis sebelum 5.)

Sebagai akibat wajar dari komputasi hasil yang tepat, pengaturan mode pembulatan MathContextobjek dengan pengaturan presisi 0 tidak digunakan dan dengan demikian tidak relevan. Dalam kasus pembagian, hasil bagi yang tepat dapat memiliki ekspansi desimal yang panjang tak terhingga; misalnya, 1 dibagi 3.

Jika hasil bagi memiliki ekspansi desimal nonterminating dan operasi ditentukan untuk mengembalikan hasil yang tepat, sebuah ArithmeticExceptiondilemparkan. Kalau tidak, hasil pasti divisi dikembalikan, seperti yang dilakukan untuk operasi lain.

Untuk memperbaikinya, Anda perlu melakukan sesuatu seperti ini :

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

di mana 2 adalah skala dan RoundingMode.HALF_UP adalah mode pembulatan

Untuk lebih jelasnya lihat posting blog ini .


3
ini juga berfungsi untuk kesalahan jasper, terima kasih community.jaspersoft.com/questions/528968/…
shareef

27
2 TIDAK precision; itu scale. Silakan lihat docs.oracle.com/javase/7/docs/api/java/math/…
John Manko

(BigDecimal baru (100)). Divide (BigDecimal baru (0,90), 2, RoundingMode.HALF_UP)
egemen

@AnandVarkeyPhilips Ini adalah skalanya. Lihat Javadoc . Edit ditolak.
Marquis of Lorne

@ user207421, saya tidak sengaja mengeditnya dan mencoba mengembalikan .. Tapi tidak punya cukup poin untuk menghapus suntingan .... meta.stackexchange.com/questions/80933/…
Anand Varkey Philips

76

Karena Anda tidak menentukan presisi dan mode pembulatan. BigDecimal mengeluh bahwa itu dapat menggunakan 10, 20, 5000, atau tempat desimal tak terhingga, dan itu masih tidak akan dapat memberikan Anda representasi yang tepat dari angka tersebut. Jadi, bukannya memberi Anda BigDecimal yang salah, itu hanya membuat Anda kesal.

Namun, jika Anda menyediakan RoundingMode dan presisi, maka itu akan dapat mengkonversi (mis. 1.333333333-hingga-infinity ke sesuatu seperti 1,3333 ... tetapi Anda sebagai programmer perlu memberi tahu itu presisi yang Anda senangi dengan '



13

Untuk memperbaiki masalah seperti itu saya telah menggunakan kode di bawah ini

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

2 presisi. Sekarang masalah terselesaikan.


3
Selain kode, beberapa penjelasan harus disediakan.
Martin Serrano

11
2 TIDAK precision; itu scale. Silakan lihat docs.oracle.com/javase/7/docs/api/java/math/…
John Manko

3
RoundingMode.HALF_EVEN direkomendasikan untuk aplikasi keuangan. Inilah yang digunakan dalam perbankan
ACV

Bagi mereka, yang bingung dengan komentar John Mankos tentang presisi, silakan lihat jawaban ini stackoverflow.com/questions/4591206/…
Stimpson Cat

5

Saya memiliki masalah yang sama, karena baris kode saya adalah:

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

Saya mengubah ini, membaca Jawaban sebelumnya, karena saya tidak menulis ketepatan desimal:

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

4 adalah Precimal Precison

DAN RoundingMode adalah konstanta Enum, Anda dapat memilih semua ini UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

Dalam Kasus ini HALF_UP, akan memiliki hasil ini:

2.4 = 2   
2.5 = 3   
2.7 = 3

Anda dapat memeriksa RoundingModeinformasinya di sini: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/


4 adalah skalanya, bukan presisi.
Marquis of Lorne

3

Ini masalah pembulatan hasil, solusi bagi saya adalah sebagai berikut.

divider.divide(dividend,RoundingMode.HALF_UP);

1

Jawaban untuk BigDecimal melempar 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")));
    }

Tambahkan objek MathContext dalam pemanggilan metode membagi Anda dan sesuaikan mode presisi dan pembulatan. Ini akan memperbaiki masalah Anda


0

Program Anda tidak tahu presisi apa untuk angka desimal yang digunakan sehingga ia melempar:

java.lang.ArithmeticException: Non-terminating decimal expansion

Solusi untuk memotong pengecualian:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.