Số học ngoại lệ: Mở rộng thập phân không kết thúc; không có kết quả thập phân có thể biểu diễn chính xác


507

Tại sao đoạn mã sau nêu ra ngoại lệ hiển thị bên dưới?

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

Ngoại lệ:

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

Câu trả lời:


843

Từ các tài liệu Java 11BigDecimal :

Khi một MathContextđối tượng được cung cấp với cài đặt chính xác bằng 0 (ví dụ MathContext.UNLIMITED:), các phép toán số học là chính xác, cũng như các phương thức số học không có MathContextđối tượng. (Đây là hành vi duy nhất được hỗ trợ trong các bản phát hành trước 5.)

Như một hệ quả của việc tính toán kết quả chính xác, cài đặt chế độ làm tròn của một MathContextđối tượng có cài đặt chính xác là 0 không được sử dụng và do đó không liên quan. Trong trường hợp chia, thương số chính xác có thể có phần mở rộng thập phân dài vô hạn; ví dụ: 1 chia cho 3.

Nếu thương số có phần mở rộng thập phân cực đại và thao tác được chỉ định để trả về kết quả chính xác, thì ArithmeticExceptionsẽ bị ném. Mặt khác, kết quả chính xác của bộ phận được trả về, như được thực hiện cho các hoạt động khác.

Để khắc phục, bạn cần làm một cái gì đó như thế này :

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

Trong đó 2 là tỷ lệ và RoundingMode.HALF_UP là chế độ làm tròn

Để biết thêm chi tiết xem bài viết blog này .


3
điều này cũng có tác dụng đối với lỗi jasper, cảm ơn Community.jaspersoft.com/questions/528968/ trên
shareef

27
2 là KHÔNG precision; nó scale. Vui lòng xem docs.oracle.com/javase/7/docs/api/java/math/iêu
John Manko

(BigDecimal mới (100)). chia (BigDecimal mới (0,90), 2, RoundingMode.HALF_UP)
egemen

@AnandVarkeyPhilips Đó là quy mô. Xem Javadoc . Chỉnh sửa bị từ chối.
Hầu tước Lorne

@ user207421, tôi đã vô tình chỉnh sửa nó và cố gắng hoàn nguyên .. Nhưng không có đủ điểm để xóa một chỉnh sửa .... meta.stackexchange.com/questions/80933/ Lỗi
Anand Varkey Philips

76

Bởi vì bạn không chỉ định độ chính xác và chế độ làm tròn. BigDecimal đang phàn nàn rằng nó có thể sử dụng các số thập phân 10, 20, 5000 hoặc vô cực, và nó vẫn không thể cung cấp cho bạn một đại diện chính xác của số. Vì vậy, thay vì cung cấp cho bạn một BigDecimal không chính xác, nó chỉ đánh vào bạn.

Tuy nhiên, nếu bạn cung cấp RoundingMode và độ chính xác, thì nó sẽ có thể chuyển đổi (ví dụ: 1.333333333 thành vô cùng thành một cái gì đó như 1.3333 ... nhưng bạn là lập trình viên cần nói cho nó biết bạn đang hài lòng với độ chính xác nào '.



13

Để khắc phục sự cố như vậy tôi đã sử dụng mã bên dưới

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

2 là độ chính xác. Bây giờ vấn đề đã được giải quyết.


3
Ngoài mã, một số giải thích nên được cung cấp.
Martin Serrano

11
2 là KHÔNG precision; nó scale. Vui lòng xem docs.oracle.com/javase/7/docs/api/java/math/ory
John Manko

3
RoundingMode.HALF_EVEN được khuyến nghị cho các ứng dụng tài chính. Đây là những gì được sử dụng trong ngân hàng
ACV

Đối với những người bối rối trước nhận xét về độ chính xác của John Mankos, vui lòng xem câu trả lời này stackoverflow.com/questions/4591206/iêu
Mèo

5

Tôi gặp vấn đề tương tự, bởi vì dòng mã của tôi là:

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

Tôi thay đổi điều này, đọc Câu trả lời trước đó, vì tôi không viết chính xác thập phân:

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

4 là số thập phân

AND RoundingMode là các hằng số Enum, bạn có thể chọn bất kỳ thứ nào trong số này UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

Trong trường hợp này HALF_UP, sẽ có kết quả này:

2.4 = 2   
2.5 = 3   
2.7 = 3

Bạn có thể kiểm tra RoundingModethông tin tại đây: http://www.javabeat.net/precise-rounding-of-decimals-USE-rounding-mode-enumutions/


4 là thang đo, không phải là độ chính xác.
Hầu tước Lorne

3

Đó là vấn đề làm tròn kết quả, giải pháp cho tôi là như sau.

divider.divide(dividend,RoundingMode.HALF_UP);

1

Trả lời cho BigDecimal ném ArithaturesException

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")));
    }

Thêm đối tượng MathContext trong lệnh gọi phương thức chia của bạn và điều chỉnh độ chính xác và chế độ làm tròn. Điều này sẽ khắc phục vấn đề của bạn


0

Chương trình của bạn không biết độ chính xác cho các số thập phân sẽ sử dụng để nó ném:

java.lang.ArithmeticException: Non-terminating decimal expansion

Giải pháp bỏ qua ngoại lệ:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.