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.
Jason
sumber

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 .

DVK
sumber
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 '

David Bullock
sumber
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.

Prahlad
sumber
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/

Alex Montenegro1987
sumber
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);
Jorge Santos Neill
sumber
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

Poorna Chander
sumber
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
Miloš Ojdanić
sumber