Подтвердить что ты не робот

Неправильное округление поплавка при использовании ToString ( "F1" )

У меня есть значение float: 12345.6489

Когда я форматирую это, используя:

(12345.6489f).ToString( "F1" )

Тогда я получаю результат

12345,7

Но это неверно, так как это должно быть 12345.6.

Кто-нибудь понимает, почему это может произойти? Еще один намек заключается в том, что кастинг для двойного перед форматированием возвращает правильный результат, и если мое значение float немного меньше, например 1234.6489, то и я получаю правильный результат.

4b9b3361

Ответ 1

Это, похоже, связано с вопросом, который я задал некоторое время назад: Round-two error в методе .NET Double.ToString

Обратите внимание, что если вы назовете .ToString("G") на свой номер, он будет правильно округлен до 12345.65. Если вы округлите округленное число, до одного десятичного знака, проблема возникает.

Когда я исследовал свой собственный вопрос раньше, я также нашел несколько примеров, которые не могли быть объяснены как ошибки круглого раза, поэтому также проверяйте этот поток.

Дополнение: Обратите внимание, что любое число, которое может быть представлено (точно) с помощью float, также может быть представлено (с большим количеством нулевых бит) на double. Можно использовать следующий трюк (который также упоминается в вопросе):

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

Ответ 2

Спасибо за этот вопрос! Очень интересно заниматься исследованиями. Но я хотел упомянуть другую сторону медали. Вы спросили следующее:

(12345.6489f).ToString( "F1" )

Тогда я получаю результат

12345,7

Но это неверно, так как это должно быть 12345.6.

Ну, мне интересно, как вы поняли, что правильно и что такое неправильный вывод этой строковой процедуры форматирования? Эти строки форматирования не должны использоваться для округления. И документация явно говорит об этом:

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


Честно говоря, когда я впервые посмотрел номер из вашего вопроса, первая идея заключалась в алгоритме округления, о котором упоминал Ханс Пассант в своем ответе. Итак, я даже не удивлен, что такой алгоритм был выбран, он на самом деле довольно интуитивно понятен:) Я даже не удивлюсь, что они рассмотрят простой усеченный как алгоритм форматирования чисел с плавающей запятой. Он будет по-прежнему довольно точным и достоверным.

Итак, несмотря на то, что все это очень интересно и выглядит как ошибка/парадокс/чудо, это на самом деле просто наши неправильные ожидания от функции, которая предназначена для выполнения (и на самом деле довольно хорошо) другой вещи.