У меня есть следующий код:
int a = Convert.ToInt32(4.5m);
int b = Convert.ToInt32(5.5m);
Console.WriteLine(a);
Console.WriteLine(b);
И вот вывод:
4
6
Почему Convert.ToInt32
округляет десятичные значения до ближайшего четного числа?
У меня есть следующий код:
int a = Convert.ToInt32(4.5m);
int b = Convert.ToInt32(5.5m);
Console.WriteLine(a);
Console.WriteLine(b);
И вот вывод:
4
6
Почему Convert.ToInt32
округляет десятичные значения до ближайшего четного числа?
Преобразование выполняется округлением до ближайшего или округления банкира:
Поведение этого метода следует стандарту IEEE 754, раздел 4. Это вид округления иногда называют округлением до ближайшего, или банкира округления. Он минимизирует ошибки округления, которые являются результатом последовательного округляя среднее значение в одном направлении.
Чтобы управлять типом округления, используемым методом Round, вызовите Перегрузка Math.Round(Double, MidpointRounding).
int a = (int)Math.Floor(4.5m);
int b = (int)Math.Floor(5.5m);
Или:
int a = decimal.ToInt32(4.5m);
int b = decimal.ToInt32(4.5m)
Вы также можете просто использовать явный оператор int cast:
int a = (int) 4.5m;
int b = (int) 5.5m;
Но прочитайте это примечание от MSDN:
Этот оператор поддерживает явное преобразование десятичного числа в Int32. Синтаксис для таких явных преобразований зависит от языка, а отдельные компиляторы языка могут предоставлять разные реализации и возвращать разные результаты. В этом примере показаны различные возвращаемые значения, когда вы явно конвертируете десятичное значение в значение Int32 с помощью С# и Visual Basic. Чтобы выполнить преобразование, не зависящее от языка, вы можете вызвать метод ToInt32 или Convert.ToInt32 (десятичный).
Math.Floor Method (Decimal)
Возвращает наибольшее целое число, меньшее или равное указанному десятичному числу.
Обратите внимание, что десятичное значение больше, чем int
, поэтому, если значение больше, чем int.MaxValue
, вы получаете OverflowException
Math.Round() позволяет вам выбрать
Console.WriteLine(Math.Round(4.5m, 0, MidpointRounding.ToEven)); //4
Console.WriteLine(Math.Round(5.5m, 0, MidpointRounding.ToEven)); //6
Console.WriteLine(Math.Round(4.5m, 0, MidpointRounding.AwayFromZero)); //5
Console.WriteLine(Math.Round(5.5m, 0, MidpointRounding.AwayFromZero)); //6
(И, как вы предполагали, значение по умолчанию - ToEven
)
Он делает это, потому что то, как оно определено (см. ниже по причине):
Возвращает: значение, округленное до ближайшего 32-разрядного целого числа со знаком. Если значение на полпути между двумя целыми числами, четное число возвращается; что равна 4,5, преобразуется в 4, а 5.5 преобразуется в 6.
вам нужно использовать что-то вроде Math.Floor
, если вам нужны разные результаты.
Документация для Math.Round
, которая делает то же самое, указывает на причину:
Поведение этого метода следует стандарту IEEE 754, раздел 4. Это вид округления иногда называют округлением до ближайшего, или банкира округления. Он минимизирует ошибки округления, которые являются результатом последовательного округляя среднее значение в одном направлении.
Чтобы управлять типом округления, используемым методом Round (Decimal) вызовите перегрузку Math.Round(десятичная, средняя точка).
Я вчера что-то прочитал, когда при округлении происходит округление до ближайшего четного числа, его называемые банкиры округляются. Вы должны сказать, как вы хотите округлить
EDIT: вы попросили объяснить, почему оно округляется до ближайшего четного числа.
скажем, что у вас 10 чисел (это крайний случай
1,5, 2.5, 3,5, 4.5, 5,5, 6,5, 7.5, 8,5, 9,5, 10.5
сумма = 60
если вы сначала обходите вокруг них
сумма = 65, потому что они будут округлены вверх
если вы банкиры вокруг них
сумма = 60
Из http://msdn.microsoft.com/en-us/library/93kx4xke
Возвращаемое значение
Тип: значение System.Int32, округленное до ближайшей 32-разрядной подписки целое число. Если значение находится на полпути между двумя целыми числами, четное число возвращается; то есть 4,5 преобразуется в 4, а 5.5 - преобразован в 6.