Tôi bắt đầu sử dụng Sonar gần đây trong một dự án, và tôi có một quy tắc PMD bị hỏng về việc sử dụng hàm tạo new BigDecimal(double val)
. Khi tôi đọc tài liệu java, tôi thấy rằng BigDecimal (double val) mới có phần không thể đoán trước và tôi nên sử dụng new BigDecimal(String val)
có thể dự đoán được.Unpredictability của BigDecimal (double) constructor
Đây là những gì javadoc nói cho BigDecimal
public BigDecimal(double val)
:
dịch một đôi vào một BigDecimal đó là chính xác thập phân đại diện của giá trị dấu chấm động nhị phân của đôi. Tỷ lệ của BigDecimal được trả lại là giá trị nhỏ nhất sao cho (10scale × val) là một số nguyên.
Ghi chú:
Kết quả của hàm tạo này có thể hơi khó lường. Một có thể giả định rằng văn bản
new BigDecimal(0.1)
trong Java tạo ra mộtBigDecimal
đó là chính xác bằng 0,1 (một giá trị chưa định tỷ lệ trong tổng số 1, với tỷ lệ 1), nhưng nó thực sự là tương đương với 0,1000000000000000055511151231257827021181583404541015625. Điều này là bởi vì 0,1 không thể được biểu diễn chính xác như là một đôi (hoặc, cho rằng vấn đề, như là một phần nhị phân của bất kỳ chiều dài hữu hạn). Do đó, giá trị đang được truyền vào hàm khởi tạo không chính xác bằng 0,1, mặc dù xuất hiện.Các chuỗi nhà xây dựng, mặt khác, là hoàn toàn có thể dự đoán: viết
new BigDecimal("0.1")
tạo ra mộtBigDecimal
đó là chính xác bằng 0.1, như người ta mong đợi. Do đó, thường là khuyến cáo rằng hàm tạo String được sử dụng tùy chọn này là .Khi tăng gấp đôi phải được sử dụng làm nguồn cho số
BigDecimal
, lưu ý rằng hàm tạo này cung cấp một chuyển đổi chính xác; nó không đưa ra kết quả tương tự khi chuyển đổi gấp đôi thành Chuỗi bằng cách sử dụng phương thứcDouble.toString(double)
và sau đó sử dụng phương thức khởi tạoBigDecimal(String)
. Để có được kết quả đó, hãy sử dụng phương thức tĩnhvalueOf(double)
.
Tại sao hàm tạo này thực sự tồn tại? Isnt new BigDecimal(String val)
có đủ cho vấn đề đó không? Khi nào tôi nên sử dụng hàm tạo new BigDecimal(double val)
?
Vì vậy, nếu tôi đang làm việc với một giá trị kép và chuyển đổi thành chuỗi, sau đó thành lớn, tôi mất độ chính xác? Sử dụng ví dụ Double.toString? – gdfbarbosa
Bạn làm, bởi vì Double.toString() là một con thú khôn lanh. Nó không thực sự trả lại giá trị chính xác của double bạn đang truyền cho nó. thay vào đó, nó trả về chuỗi ngắn nhất, khi được phân tích cú pháp, sẽ vẫn được chuyển đổi thành chính xác giá trị kép được chỉ định. Đó là một chút khó hiểu, nhưng về cơ bản, nó có nghĩa là nếu Double.toString (0.100000000000000005551115123) là "0.1", thì nó được đảm bảo rằng Double.parseDouble ("0.1") cũng là 0.100000000000000005551115123. Và điều phức tạp này là lý do tại sao bạn mất độ chính xác, nhưng nó không bao giờ trông giống như khi bạn in giá trị kép của mình lên bàn điều khiển. – LordOfThePigs
Mất chính xác xảy ra vì BigDecimal mới (Double.toString (0.1d)), thực sự đại diện cho giá trị "0.1" chính xác, mặc dù 0.1d không thực sự bằng 0.1 (vì nó thực sự là 0.100000000000000005551115123). Trong một số trường hợp, hành vi có thể được mong muốn, nhưng trong một số trường hợp khác, đó là một sự mất cân bằng không thể chấp nhận được. – LordOfThePigs