2013-03-28 36 views
7

Ai có thể giải thích tại sao trên Trái đất, những biểu thức "giống hệt" này trả về các giá trị khác nhau?Android: lỗi làm tròn java. Không thể hiểu tại sao?

(new BigDecimal(String.valueOf(131.7d))).multiply(new BigDecimal(String.valueOf(0.95d))).doubleValue() = 125.115 

(new BigDecimal(    131.7d)).multiply(new BigDecimal(    0.95d)).doubleValue() = 125.11499999999998 

BigDecimal đang làm gì khác nhau giữa chúng?

+1

để những người bỏ phiếu đóng gần như trùng lặp, các câu hỏi tương tự nhưng không trùng lặp. – Woot4Moo

Trả lời

5

Nếu bạn đọc tài liệu API, bạn sẽ thấy taht String.valueOf(dobule) sử dụng Double.toString(double) để định dạng giá trị. Có thể không rõ ràng, nhưng Double.toString(double) làm tròn giá trị, trước khi định dạng nó thành một chuỗi:

Có bao nhiêu chữ số được in cho phần phân đoạn của m hoặc a? Phải có ít nhất một chữ số để đại diện cho phần phân số và vượt quá số lượng đó, nhưng chỉ cần nhiều, nhiều chữ số càng cần để phân biệt duy nhất giá trị đối số từ các giá trị liền kề loại kép. Đó là, giả sử rằng x là giá trị toán học chính xác được biểu diễn bằng biểu diễn thập phân được tạo ra bởi phương pháp này cho một đối số không đồng nhất hữu hạn d. Sau đó, d phải là giá trị gấp đôi gần nhất đến x; hoặc nếu hai giá trị tăng gấp đôi là bình đẳng gần với x, sau đó d phải một trong số họ và các bit quan trọng nhất của significand của d phải được 0.

Kết quả của việc này là String.valueOf(131.7d) sẽ trả lại chuỗi "131.7" ngay cả khi giá trị chính xác của đối số là 131.69999999999998863131622783839702606201171875. Lý do cho điều này là phân số thập phân không phải lúc nào cũng được biểu diễn chính xác bằng cách sử dụng phân số nhị phân (như được sử dụng với phao và tăng gấp đôi).

Vì vậy, mới new BigDecimal(String.valueOf(131.7)) sẽ tạo một BigDecimal với giá trị chính xác 131,7. new BigDecimal(131.7) sẽ tạo một BigDecimal với giá trị chính xác 131.69999999999998863131622783839702606201171875.

+0

Điều đó giải thích vấn đề. Cảm ơn bạn! – Christian

6

Nếu bạn nhìn vào API documentation:

BigDecimal(double val) 
      Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. 

so

BigDecimal(String val) 
      Translates the string representation of a BigDecimal into a BigDecimal. 

Đây là trong thực tế không phải là điều tương tự. Trong hàm tạo double, nó đang sử dụng một số dấu phẩy động (vốn không chính xác). Trong hàm tạo String, nó đang lấy giá trị chính xác mà bạn đã cung cấp và không phải là thực hiện chuyển đổi điểm nổi. Vì vậy, điều này thực tế có nghĩa là các hàm tạo ở trên không phải là các biểu thức "giống nhau"

+0

Vì vậy, không có cách nào khác để có được giá trị "chính xác" của phép tính này (131,7 * 0,95 = 125.115) so với giá trị chuyển đổi thành chuỗi trước khi chuyển nó sang BigDecimal? Điều này có vẻ rất lạ với tôi! – Christian

+0

Tôi không hiểu tại sao 2 hàm tạo có cùng giá trị đầu vào, trả về 2 kết quả khác nhau. Nếu Double.valueOf (String.valueOf (131.7d)) == 131.7d, tại sao BigDecimal trả về các giá trị khác nhau? Nó không có ý nghĩa với tôi! – Christian

+2

Hmm, bạn thực sự không trả lời câu hỏi của Christian ở đây, kể từ khi ông bắt đầu với 131,7d và 0,95d trong cả hai trường hợp. Lý do cho sự khác biệt mà anh ta quan sát không phải vì các constructor BigDecimal khác nhau, nhưng String.valueOf (dobule) đó gián tiếp làm tròn đối số trước khi chuyển đổi thành một chuỗi và không trả về một chuỗi với giá trị chính xác của đối số. – jarnbjo

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