Неправильное округление поплавка при использовании ToString ( "F1" )
У меня есть значение float: 12345.6489
Когда я форматирую это, используя:
(12345.6489f).ToString( "F1" )
Тогда я получаю результат
12345,7
Но это неверно, так как это должно быть 12345.6.
Кто-нибудь понимает, почему это может произойти? Еще один намек заключается в том, что кастинг для двойного перед форматированием возвращает правильный результат, и если мое значение float немного меньше, например 1234.6489, то и я получаю правильный результат.
Ответы
Ответ 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]()
Честно говоря, когда я впервые посмотрел номер из вашего вопроса, первая идея заключалась в алгоритме округления, о котором упоминал Ханс Пассант в своем ответе. Итак, я даже не удивлен, что такой алгоритм был выбран, он на самом деле довольно интуитивно понятен:) Я даже не удивлюсь, что они рассмотрят простой усеченный как алгоритм форматирования чисел с плавающей запятой. Он будет по-прежнему довольно точным и достоверным.
Итак, несмотря на то, что все
это очень интересно и выглядит как ошибка/парадокс/чудо, это на самом деле просто наши неправильные ожидания от функции, которая предназначена для выполнения (и на самом деле довольно хорошо) другой вещи.