2012-08-29 31 views
6

thể trùng lặp:
ArithmeticException thrown during BigDecimal.divideChia BigDecimals kết quả trong ArithmeticException

Điều này dẫn đến ArithmeticException: http://ideone.com/RXeZw

Cung cấp một quy mô và phương thức làm tròn sẽ cho tôi kết quả sai. Ví dụ này sẽ xuất 50,03%. Làm thế nào để tròn này một cách chính xác?

Để tham khảo dễ dàng hơn, đây là đoạn code:

BigDecimal priceDiff = BigDecimal.ONE 
    .subtract(new BigDecimal(9.99) 
    .divide(new BigDecimal(19.99))) 
    .multiply(new BigDecimal(100)); 
System.out.println(priceDiff.toPlainString()); 

Trả lời

9

BigDecimal.divide(BigDecimal divisor) ném một ArithmeticException nếu kết quả không thể được đại diện một cách chính xác.
Bạn sẽ phải sử dụng cung cấp MathContext hoặc RoundingMode cho biết cách bạn muốn xử lý việc này. Ví dụ:

public class Test { 
    public static void main(String[] args) throws java.lang.Exception { 
     BigDecimal priceDiff = BigDecimal.ONE.subtract(new BigDecimal("9.99").divide(new BigDecimal("19.99"), MathContext.DECIMAL128)) 
              .multiply(new BigDecimal(100)); 
     System.out.println(priceDiff.toPlainString()); 
    } 
} 

công trình và in

50.0250125062531265632816408204102100 

Ngoài ra, lưu ý việc sử dụng các BigDecimal(String) constructor để tránh các vấn đề khi bạn tạo BigDecimal sử dụng một double chữ.

4

Bạn nên sử dụng một MathContext như bộ phận của bạn như vô số thập phân:

BigDecimal priceDiff = BigDecimal.ONE 
      .subtract(new BigDecimal(9.99) 
      .divide(new BigDecimal(19.99), new MathContext(10, RoundingMode.UP))) 
      .multiply(new BigDecimal(100)); 
    System.out.println(priceDiff.toPlainString()); 

Tuy nhiên, đó in 50,025 ...

này sẽ in 49,98:

BigDecimal priceDiff = new BigDecimal(9.99) 
     .divide(new BigDecimal(19.99), new MathContext(10, RoundingMode.UP)) 
     .multiply(new BigDecimal(100), new MathContext(4, RoundingMode.UP)); 
System.out.println(priceDiff.toPlainString()); 
1

Các phép toán BigDecimal luôn cố tính kết quả chính xác. Thử cái này.

BigDecimal priceDiff = BigDecimal.ONE 
       .subtract(new BigDecimal(9.99) 
         .divide(new BigDecimal(19.99),RoundingMode.HALF_UP)) 
       .multiply(new BigDecimal(100)); 
     System.out.println(priceDiff.toPlainString()); 
1

Tương tự như câu trả lời @ Keppil của

double d = (1 - 9.99/19.99) * 100; 
System.out.printf("%.2f%%%n", d); 

in

50.03% 

Bạn sẽ không có được 49,98% vì đây không phải là câu trả lời cho phương trình của bạn.

+0

có, tôi chỉ bị nhầm lẫn về tất cả các số sau :-) – dtrunk

+0

@dtrunk Tôi tìm thấy bằng cách sử dụng 'double' ít khó hiểu hơn. ;) –

+0

Tôi không thể sử dụng gấp đôi vì nó sẽ gây ra quá nhiều thay đổi trong mã – dtrunk

2

Từ Javadoc:

Trong trường hợp chia, thương số chính xác có thể có một mở rộng số thập phân vô hạn dài; ví dụ, 1 chia cho 3. Nếu thương có một mở rộng thập phân không có kết quả và hoạt động được xác định để trả về một kết quả chính xác, một ArithmeticException được ném ra.

Giải pháp là cung cấp MathContext cho bộ phận, ví dụ MathContext.DECIMAL128.Nếu bạn muốn làm tròn được thực hiện theo cách thông thường (làm tròn nửa lên chứ không phải là để gần nhất số chẵn), sử dụng MathContext(int precision)

Bạn cũng nên tạo BigDecimal của bạn với String lập luận chứ không phải là double tranh cãi, bởi vì sự mất mát nguyên nhân thứ hai chính xác .

Các vấn đề liên quan