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

จากเอกสารJava 11BigDecimal :

เมื่อMathContextวัตถุได้รับการตั้งค่าความแม่นยำเป็น 0 (ตัวอย่างเช่นMathContext.UNLIMITED) การดำเนินการทางคณิตศาสตร์จะถูกต้องเช่นเดียวกับวิธีการทางคณิตศาสตร์ที่ไม่มีMathContextวัตถุ (นี่เป็นพฤติกรรมเดียวที่ได้รับการสนับสนุนในรุ่นก่อนหน้า 5)

ในฐานะที่เป็นข้อพิสูจน์ของการคำนวณผลลัพธ์ที่แน่นอนการตั้งค่าโหมดการปัดเศษของMathContextวัตถุที่มีการตั้งค่าความแม่นยำเป็น 0 จะไม่ถูกใช้และไม่เกี่ยวข้องดังนั้น ในกรณีที่มีการหารหารที่แม่นยำอาจมีการขยายทศนิยมยาวไม่สิ้นสุด ตัวอย่างเช่น 1 หารด้วย 3

หากความฉลาดมีการขยายทศนิยมที่ไม่ทำลายและการดำเนินการที่ระบุไว้เพื่อส่งกลับผลลัพธ์ที่แน่นอน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

(ใหม่ BigDecimal (100)) หาร (ใหม่ 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-to-infinity เป็น 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 คือระบบกำหนดตำแหน่งทศนิยม

และ 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

โปรแกรมของคุณไม่ทราบว่ามีความแม่นยำสำหรับตัวเลขทศนิยมที่จะใช้ดังนั้นมันจะโยน:

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.