2012-02-28 41 views
32

Tôi có một số XSD yêu cầu tôi sử dụng BigDecimal cho lat/lon. Tôi hiện có lat/lon là tăng gấp đôi và chuyển đổi chúng thành BigDecimal, nhưng tôi chỉ được yêu cầu sử dụng khoảng 12 vị trí chính xác. Tôi đã không thể tìm ra cách để thiết lập điều đó. Bất cứ ai có thể giúp tôi với điều này?Đặt độ chính xác cụ thể của BigDecimal

+0

Bạn đã cố gắng cho các nhà xây dựng một MathContext? – bdares

+1

Nếu tôi thấy chính xác, bạn đang nói về các chữ số thập phân, không phải là độ chính xác của dấu phẩy động. Ít nhất câu trả lời được chấp nhận sẽ dẫn đến 12 chữ số thập phân, chứ không phải 12 chữ số chính xác. – vbence

Trả lời

60

Bạn có thể sử dụng setScale() ví dụ:

double d = ... 
BigDecimal db = new BigDecimal(d).setScale(12, BigDecimal.ROUND_HALF_UP); 
+1

Duh. Nhìn lại lỗi mà tôi nhận được, nó nói làm tròn là cần thiết. Tôi đã chỉ thực hiện .setScale (12). Một khi tôi xác nhận nó hoạt động, tôi sẽ làm cho nó như được trả lời. Cảm ơn. – Jason

+0

Tôi không biết tại sao nó không chỉ sử dụng một phương thức làm tròn mặc định như đúc, tôi chỉ thấy ROUND_HALF_UP được sử dụng. Nó khá là giả tạo. ;) –

+1

+1 vì điều này đã giúp tôi với tự động hóa của tôi hôm nay :) – Brian

27

Tiêu đề của câu hỏi hỏi về độ chính xác. BigDecimal phân biệt giữa quy mô và độ chính xác. Tỷ lệ là số vị trí thập phân. Bạn có thể nghĩ chính xác là số lượng significant figures, còn được gọi là chữ số có nghĩa.

Một số ví dụ trong Clojure.

(.scale  0.00123M) ; 5 
(.precision 0.00123M) ; 3 

(Trong Clojure, The M chỉ định một BigDecimal đen. Bạn có thể dịch các Clojure Java nếu bạn thích, nhưng tôi thấy nó là nhỏ gọn hơn Java!)

Bạn có thể dễ dàng tăng quy mô:

(.setScale 0.00123M 7) ; 0.0M 

Nhưng bạn không thể giảm quy mô trong cùng một cách chính xác:

(.setScale 0.00123M 3) ; ArithmeticException Rounding necessary 

Bạn sẽ cần phải vượt qua một chế độ làm tròn quá:

(.setScale 0.00123M 3 BigDecimal/ROUND_HALF_EVEN) ; 
; Note: BigDecimal would prefer that you use the MathContext rounding 
; constants, but I don't have them at my fingertips right now. 

Vì vậy, nó rất dễ dàng để thay đổi quy mô. Nhưng chính xác thì sao? Đây không phải là dễ dàng như bạn có thể hy vọng!

Nó rất dễ dàng để giảm độ chính xác:

(.round 3.14159M (java.math.MathContext. 3)) ; 3.14M 

Nhưng nó không phải là rõ ràng làm thế nào để tăng độ chính xác:

(.round 3.14159M (java.math.MathContext. 7)) ; 3.14159M (unexpected) 

Đối với hoài nghi, đây là không chỉ là một số dấu 0 không được hiển thị:

(.precision (.round 3.14159M (java.math.MathContext. 7))) ; 6 
; (same as above, still unexpected) 

FWIW, Clojure là cẩn thận với số không đuôi và sẽ cho họ thấy:

4.0000M ; 4.0000M 
(.precision 4.0000M) ; 5 

lại đi đúng hướng ... Bạn có thể thử sử dụng một constructor BigDecimal, nhưng nó không được thiết lập độ chính xác cao hơn so với bất kỳ số chữ số bạn chỉ định:

(BigDecimal. "3" (java.math.MathContext. 5)) ; 3M 
(BigDecimal. "3.1" (java.math.MathContext. 5)) ; 3.1M 

Vì vậy, không có cách nào nhanh chóng để thay đổi độ chính xác. Tôi đã dành thời gian chiến đấu này trong khi viết lên câu hỏi này và với một dự án tôi đang làm việc. Tôi xem xét điều này, tốt nhất, A CRAZYTOWN API, và tồi tệ nhất là một lỗi. Những người. Nghiêm túc?

Vì vậy, tốt nhất tôi có thể nói, nếu bạn muốn thay đổi độ chính xác, bạn sẽ cần phải làm các bước sau:

  1. Lookup độ chính xác hiện hành.
  2. Tra cứu tỷ lệ hiện tại.
  3. Tính toán thay đổi tỷ lệ.
  4. Đặt quy mô mới

Những bước này, như mã Clojure:

(def x 0.000691M) ; the input number 
(def p' 1) ; desired precision 
(def s' (+ (.scale x) p' (- (.precision x)))) ; desired new scale 
(.setScale x s' BigDecimal/ROUND_HALF_EVEN) 
; 0.0007M 

tôi biết, đây là một rất nhiều bước chỉ để thay đổi chính xác!

Tại sao BigDecimal không cung cấp tính năng này? Tôi đã bỏ qua một cái gì đó?

+0

Điều gì về 'BigDecimal.round (MathContext mới (chính xác, RoundingModel.ROUND_HALF_EVEN))'? –

+1

@ PaŭloEbermann Bạn đang hỏi hoặc đề xuất? Bạn đã thử chưa? Chăm sóc chia sẻ kết quả chi tiết cho các ví dụ tôi chạy qua trong câu trả lời của tôi? Nếu vậy, tôi nghĩ rằng nó đảm bảo một câu trả lời riêng biệt. –

+1

Đối với bất kỳ ai thích tôi và không biết một chút về Clojure, tôi nghĩ giải pháp được hiển thị ở đây là 'x.setScale (x.scale() + p - x.precision(), RoundingMode.HALF_UP)', trong đó ' x' là 'BigDecimal' bạn muốn làm tròn, và' p' là số lượng các số liệu quan trọng bạn muốn giữ lại. Nó làm việc cho tôi, nhưng sửa tôi nếu tôi sai! – Nateowami

3
BigDecimal decPrec = (BigDecimal)yo.get("Avg"); 
decPrec = decPrec.setScale(5, RoundingMode.CEILING); 
    String value= String.valueOf(decPrec); 

Bằng cách này bạn có thể đặt độ chính xác cụ thể của BigDecimal.

Ở đây, giá trị của decPrec là 1,5726903423607562595809913132345426 được làm tròn đến 1,57267

0

Hãy thử mã này ...

Integer perc = 5; 
    BigDecimal spread = BigDecimal.ZERO; 
    BigDecimal perc = spread.setScale(perc,BigDecimal.ROUND_HALF_UP); 
    System.out.println(perc); 

Kết quả: 0,00000

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