2012-08-31 40 views
8

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 BigDecimalpublic 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ột BigDecimal đó 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ột BigDecimal đó 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ức Double.toString(double) và sau đó sử dụng phương thức khởi tạo BigDecimal(String). Để có được kết quả đó, hãy sử dụng phương thức tĩnh valueOf(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)?

Trả lời

5

Tại sao hàm tạo này thực sự tồn tại?

Nó chuyển đổi giá trị được biểu thị thực tế là double thành BigDecimal. Toàn bộ điểm của BigDecimal là cung cấp cho độ chính xác càng nhiều càng tốt và đó là những gì nhà xây dựng này làm.

Nếu bạn muốn để có những giá trị mà bạn sẽ nhận được với một lượng nhỏ làm tròn các Double.toString(double) sử dụng bạn có thể sử dụng

System.out.println(BigDecimal.valueOf(0.1)); 

in

0.1 

Khi nào tôi nên sử dụng BigDecimal mới (double val) constructor

Khi bạn muốn biết giá trị double thực sự đại diện. Bạn có thể áp dụng làm tròn của riêng bạn theo yêu cầu.

Khi bạn sử dụng double, bạn nên luôn áp dụng làm tròn hợp lý. Nhưng, nếu bạn đã làm điều đó bạn có thể tìm thấy bạn không cần BigDecimal. ;)

2

Bởi vì nếu bạn đã bắt đầu với giá trị double làm dữ liệu, bạn đã mất quyền chọn đó. Vì vậy, không có nó sẽ buộc bạn phải chuyển đổi nó để String cho BigDecimal để chuyển đổi nó trở lại.

Và cũng có thể, đôi khi bạn chỉ cần giá trị.

+0

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

+3

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

+1

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

1

Bạn sẽ sử dụng hàm tạo kép khi dữ liệu bạn muốn làm việc đã tồn tại dưới dạng giá trị kép. Có để chuyển đổi nó thành một chuỗi trước khi chuyển đổi nó sang BigDecimal sẽ là một lãng phí trong trường hợp đó.

1

When should I use the new BigDecimal(double val) constructor?

Tốt hơn - không nơi nào.

Nếu bạn sẵn sàng chơi với BigDecimals, sử dụng hàm tạo với phương tiện kép sẽ mất tất cả lợi ích của việc trình bày số chính xác.

Why does this constructor really exists?

Bởi vì đôi khi bạn chỉ có đôi, mà bạn muốn dịch sang BigDecimal. Buộc bạn sử dụng .toString() Inbetween sẽ chỉ là ngớ ngẩn;)

0

tôi muốn bình luận, nhưng không thể tìm cách đặt "code" vào bình luận, vì vậy tôi trả lời:

double val = 0.1; // this is not 0.1, but an approximination as pointed out in other answers. BigDecimal biggy = new BigDecimal(val); // this variable conatains the "same" value as val does, however it is not 0.1, but as pointed out in other answers: 0.100000000000000005551115123

Vì vậy, trong trường hợp liệt kê ở đây, nơi bạn có đầy đủ kiểm soát mã nguồn, bạn nên viết val là 'Chuỗi val = "0.1"'

Tuy nhiên, contructor BigDecimal(double val) hữu ích trong trường hợp bạn đọc nhị phân tăng gấp đôi từ tệp. Rõ ràng bạn sẽ muốn trong hầu hết các trường hợp BigDecimals giống hệt như 'đôi'

0

Không thể đoán trước? Tôi không đồng ý.

final double before = 0.1; 
BigDecimal bd = new BigDecimal(before); 
double after = bd.doubleValue(); 
assert before == after; 

chìa khóa để hiểu:

assert 0.1 == 0.1000000000000000055511151231257827021181583404541015625; 

Nếu bạn thực sự có nghĩa là "0.1", sau đó có, sử dụng constructor String =) Nhưng nếu bạn có một double đã có, sau đó đôi không phải là "0.1 ".

Các javadoc bạn trích dẫn nói:

Khi một đôi phải được sử dụng như một nguồn cho một BigDecimal, lưu ý rằng constructor này cung cấp một chính xác chuyển đổi;

Tôi không thấy cách chuyển đổi chính xác là "không thể đoán trước" và tôi rất có lợi khi xóa từ "phải" khỏi trích dẫn này.

Vào cuối ngày, cả hai nhà thầu hoạt động giống như dự định. Nếu bạn có Chuỗi "0,1", thì BigDecimal (Chuỗi) chuyển đổi giá trị này chính xác. Nếu bạn có một đôi 0,1, sau đó BigDecimal (double) chuyển đổi giá trị này chính xác.