2013-01-14 28 views
11

Tôi có một giá trị float: 12345,6489làm tròn không đúng phao khi sử dụng ToString ("F1")

Khi tôi định dạng này sử dụng:

(12345.6489f) ToString ("F1")

Sau đó, tôi nhận được một kết quả của

12345,7

Nhưng điều này là không chính xác, vì nó phải được 12.345,6.

Có ai hiểu tại sao điều này có thể xảy ra không? Một gợi ý khác là việc tạo gấp đôi trước khi định dạng của tôi trả lại kết quả chính xác và nếu giá trị float của tôi nhỏ hơn một chút, ví dụ 1234.6489, thì tôi cũng nhận được kết quả chính xác.

+1

@DavidStratton: 'Double' cũng không chính xác và sẽ mang lại những điều kỳ lạ tương tự. Họ chỉ có các phạm vi khác nhau và các phạm vi khác nhau. –

+0

@JonSkeet - cảm ơn vì đã làm rõ! Tôi đã xóa nhận xét. – David

+0

Single.ToString đang làm điều gì đó rất kỳ quặc. Tôi nghĩ bạn sẽ cần phải nhìn vào IL. Tài liệu (http://msdn.microsoft.com/en-us/library/f71z6k0c.aspx) nói "Theo mặc định, giá trị trả lại chỉ chứa 7 chữ số chính xác mặc dù tối đa 9 chữ số được duy trì trong nội bộ" nhưng tôi ' m chắc chắn tôi không có ý tưởng đó có nghĩa là gì. –

Trả lời

2

này dường như có liên quan đến một câu hỏi tôi hỏi một số thời gian trước đây: Round-twice error in .NET's Double.ToString method

Lưu ý rằng nếu bạn gọi .ToString("G") vào số của bạn, nó được làm tròn một cách chính xác để 12345.65. Nếu bạn làm tròn số tròn, đến một số thập phân, vấn đề sẽ xảy ra.

Khi tôi điều tra câu hỏi của riêng mình trước đó, tôi cũng tìm thấy một số ví dụ không thể giải thích là lỗi hai lần, vì vậy hãy kiểm tra chuỗi đó.

Bổ sung: Lưu ý rằng bất kỳ số nào có thể được biểu diễn (chính xác) bởi float, cũng có thể được biểu diễn (với nhiều bit không) theo double. Người ta có thể sử dụng thủ thuật sau (câu hỏi cũng đề cập đến):

float x = 12345.6489f; 
string trick = ((double)x).ToString("F1"); 
1

Cảm ơn câu hỏi này! Điều rất thú vị là phải tham gia vào các cuộc điều tra. Nhưng tôi muốn đề cập đến bên kia của một huy chương. Bạn hỏi như sau:

(12345.6489f) ToString ("F1")

Sau đó, tôi nhận được một kết quả của

12345,7

Nhưng điều này là không chính xác, vì nó phải được 12345,6.

Vâng, tôi đang tự hỏi làm thế nào bạn đã tìm ra đúng là gì và sai đầu ra của chuỗi này định dạng thông thường là gì? Những chuỗi định dạng này không được dùng để làm tròn mục đích. Và tài liệu hướng dẫn rõ ràng says về nó:

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#FFormatString


Thành thực mà nói khi tôi lần đầu tiên nhìn ở vị trí thứ từ câu hỏi của bạn - ý tưởng đầu tiên là về làm tròn số thuật toán mà Hans passant đề cập trong câu trả lời của mình. Vì vậy, tôi thậm chí không ngạc nhiên rằng thuật toán như vậy đã được chọn, nó thực sự là khá trực quan :) Tôi thậm chí sẽ không ngạc nhiên khi họ sẽ xem xét truncate đồng bằng như thuật toán để định dạng số điểm nổi.Nó sẽ vẫn khá chính xác và hợp lệ. Vì vậy, mặc dù thực tế là tất cả điều này rất thú vị và trông giống như một lỗi/nghịch lý/phép lạ, điều này thực tế chỉ là mong đợi sai lầm của chúng tôi từ chức năng được thiết kế để thực hiện (và thực sự hoạt động tốt) cái khác.

+0

Ah tôi nghĩ rằng tôi đã đọc ở đâu đó rằng định dạng chuỗi sẽ làm tròn số cho bạn, đó là lý do tại sao tôi nghĩ rằng 12345.6 sẽ là câu trả lời đúng. Có Math.Round chắc chắn sẽ đáng tin cậy hơn! –

+0

Math.Round không giúp gì cả. Điều đó trả về một giá trị dấu chấm động. Bạn vẫn cần phải nhận được một chuỗi mà sẽ đưa bạn trở lại ToString. Bạn cần làm tròn như một phần của chuyển đổi thành chuỗi. Điều này là quan trọng bởi vì dấu chấm động sử dụng biểu diễn nhị phân, nhưng biểu diễn chuỗi là số thập phân. –

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