Почему .NET использует округляющийся алгоритм в Строке. Формат, который несовместим с Математикой по умолчанию. Вокруг () алгоритм?

Я заметил следующее несоответствие в C#/.NET. Я задавался вопросом, почему это так.

Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.04, Math.Round(1.04, 1));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.05, Math.Round(1.05, 1));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.06, Math.Round(1.06, 1));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.14, Math.Round(1.14, 1));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.15, Math.Round(1.15, 1));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.16, Math.Round(1.16, 1));
Console.WriteLine();
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.04, Math.Round(1.04, 1, MidpointRounding.AwayFromZero));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.05, Math.Round(1.05, 1, MidpointRounding.AwayFromZero));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.06, Math.Round(1.06, 1, MidpointRounding.AwayFromZero));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.14, Math.Round(1.14, 1, MidpointRounding.AwayFromZero));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.15, Math.Round(1.15, 1, MidpointRounding.AwayFromZero));
Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.16, Math.Round(1.16, 1, MidpointRounding.AwayFromZero));

Вывод:

1.0  | 1.0
1.1  | 1.0
1.1  | 1.1
1.1  | 1.1
1.2  | 1.2
1.2  | 1.2

1.0  | 1.0
1.1  | 1.1
1.1  | 1.1
1.1  | 1.1
1.2  | 1.2
1.2  | 1.2

Кажется, что строковым поведением форматирования по умолчанию является к круглому использованию MidpointRounding. AwayFromZero, а не Математика. Вокруг () значение по умолчанию MidpointRounding. ToEven.

27
задан orj 9 February 2010 в 01:12
поделиться

3 ответа

Как историческая справка, оригинальная реализация Visual Basic в Format$ также не соответствовала округлому округлению, так называемому Banker's Rounding. Оригинальный код Format$ был написан Тимом Патерсоном. Возможно, вы помните, что Тим был автором небольшой программы под названием QDOS (позднее известной как MS-DOS), которая довольно хорошо продавалась там некоторое время.

Возможно, это еще один случай 25-летней обратной совместимости.

12
ответ дан 28 November 2019 в 05:52
поделиться

Пожалуйста, взгляните сюда: Возможная ошибка: Math.Round возвращает противоречивые результаты

WriteLine() просто вызывает Object.ToString(), что, в свою очередь, приводит к вызову Number.FormatDouble(this, null, NumberFormatInfo.CurrentInfo). Как видите, параметр для строки формата равен нулю. Если вы хотите получить реальную вещь от ToString(), то вы должны использовать System.Diagnostics.Debug.WriteLine(n.ToString("R")).

"При форматировании значения Single или Double с помощью этого спецификатора сначала проверяется общий формат с 15-ю цифрами точности для Double и 7-ю цифрами точности для Single. При успешном возврате значения к тому же числовому значению оно форматируется с помощью общего формата спецификатора. При неудачном разборе значения, оно форматируется с 17-ю цифрами точности для двойного и 9-ю цифрами точности для одиночного формата". Стандартные строки числового формата

2
ответ дан 28 November 2019 в 05:52
поделиться

WriteLine (string, params object []) вызывает string.Format и передает текущий CultureInfo, поэтому будет использовать ваш локализованный NumberFormatInfo, чтобы определить, как записать число. Math.Round не принимает во внимание региональные параметры, поскольку вы указываете, как именно вы хотите округлить.

Хм, покопавшись в Reflector, может быть, и нет :)

0
ответ дан 28 November 2019 в 05:52
поделиться