Ошибка округления C# банкира
double a = 18.565
return Math.Round(a,2)
... возвращается 18.57.
Для каждого другого числа, которое я пробовал, банковское округление работало, как и ожидалось, например, Math.Round(2.565,2) вернул 2,56.
Любая подсказка, почему и когда это происходит? Это ошибка или я что-то упускаю из-за банковского округления?
Спасибо..
4 ответа
Как сказал Мэтью, 18.565 не могут быть точно представлены. Фактическое используемое значение составляет 18,565000000000001278976924368180334568023681640625 (найдено с использованием DoubleConverter), что явно находится за пределами середины пути. Теперь у меня есть ощущение, что иногда Math.Round
будет рассматривать значение, которое на самом деле находится за пределами промежуточной точки, но которое настолько близко к половине промежуточной точки, насколько это может быть точно представлено, как находящееся именно в этой точке. Однако я не видел никакой документации, описывающей ситуации, в которых это применяется, и, очевидно, этого не происходит в этом случае. Я бы не хотел на это полагаться.
Конечно, даже округленное значение не совсем 18,57. Это на самом деле 18.57000000000000028421709430404007434844970703125.
По сути, если вы действительно, действительно хотите точно представлять десятичные значения, вы должны использовать decimal
, Это не только с точки зрения Math.Round
- это касается каждого аспекта обработки значений с плавающей запятой.
Это дает правильное значение для Math.Round
, конечно:
decimal m = 18.565m;
Console.WriteLine(Math.Round(m, 2)); // Prints 18.56
18.565 не может быть точно представлен как двойной. Таким образом, двоичное представление немного выше, поэтому оно округляется. Если вы используете десятичную:
decimal a = 18.565m;
return Math.Round(a,2)
это может быть точно представлено, и у вас не будет этой проблемы.
Я предполагаю, что представление FP означает, что на самом деле это не трейлинг 5; опасности FP!
Это работает хорошо, хотя:
decimal a = 18.565M; // <===== decimal
var s = Math.Round(a, 2);
Double - это значение с плавающей запятой, поэтому, возможно, если вы запишите его как 18.565, оно на самом деле будет в памяти что-то вроде 18.56500000000000000000000000000000001, и, следовательно, это больше, чем средняя точка.