Как округлить до ближайшего четного целого?
Моя последняя цель всегда округляется до ближайшего четного целого.
Например, номер 1122.5196
я хочу как результат 1122
. Я пробовал следующие варианты:
Math.Round(1122.5196d, 0, MidpointRounding.ToEven); // result 1123
Math.Round(1122.5196d, 0, MidpointRounding.AwayFromZero); // result 1123
В конце концов, то, что я хотел бы получить, всегда является ближайшим даже интуитивным. Например:
-
1122.51 --> 1122
-
1122.9 --> 1122
(поскольку ближайший int равен 1123
но он нечетный, а 1122
- ближе, чем 1124
) -
1123.0 --> 1124
(следующее четное значение, следующее более высокое значение)
Я работаю только с положительными цифрами.
И так далее.
Есть какой-то метод, который делает это или я должен реализовать свой собственный метод?
Ответы
Ответ 1
Попробуйте это (позвольте использовать Math.Round
с MidpointRounding.AwayFromZero
, чтобы получить "следующее четное значение", но масштабированное - 2
фактора):
double source = 1123.0;
// 1124.0
double result = Math.Round(source / 2, MidpointRounding.AwayFromZero) * 2;
Демо-версия:
double[] tests = new double[] {
1.0,
1123.1,
1123.0,
1122.9,
1122.1,
1122.0,
1121.5,
1121.0,
};
string report = string.Join(Environment.NewLine, tests
.Select(item => $"{item,6:F1} -> {Math.Round(item / 2, MidpointRounding.AwayFromZero) * 2}"));
Console.Write(report);
Результат:
1.0 -> 2 // In case of tie, next even value
1123.1 -> 1124
1123.0 -> 1124 // In case of tie, next even value
1122.9 -> 1122
1122.1 -> 1122
1122.0 -> 1122
1121.5 -> 1122
1121.0 -> 1122 // In case of tie, next even value
Ответ 2
Один лайнер:
double RoundToNearestEven(double value) =>
Math.Truncate(value) + Math.Truncate(value) % 2;
скрипка
Объяснение: если у нас есть четное число с некоторыми цифрами после с плавающей запятой, нам нужно просто избавиться от этих цифр. Если у нас есть нечетное число, нам нужно сделать то же самое, а затем перейти к следующему целому числу, которое гарантировано будет четным.
PS Благодаря @DmitryBychenko за то, что бросание двойного в длинный - не самая яркая идея.
Ответ 3
Причина, по которой вы получаете результат 1123, даже при использовании
Math.Round(1122.5196d, 0, MidpointRounding.ToEven);
потому что это именно то, что вы просили у компилятора. При округлении до десятичных знаков обязательно помните, что 1123.0 равно.
то есть. 1122.51 округляется до равно 1123.0 (обратите внимание, что, поскольку оно является десятичным, оно всегда будет хранить десятичное место, и поэтому.0 здесь делает это четным числом).
Вместо этого я бы написал функцию для этого, например:
private int round_up_to_even(double number_to_round)
{
int converted_to_int = Convert.ToInt32(number_to_round);
if (converted_to_int %2 == 0) { return converted_to_int; }
double difference = (converted_to_int + 1) - number_to_round;
if (difference <= 0.5) { return converted_to_int + 1; }
return converted_to_int - 1;
}
Ответ 4
Вот пример, который я нашел в msdn, который будет производить только ближайшие числа, кажется, подходит вашему делу хорошо,
using System;
class Example
{
public static void Main()
{
// Define a set of Decimal values.
decimal[] values = { 1.45m, 1.55m, 123.456789m, 123.456789m,
123.456789m, -123.456m,
new Decimal(1230000000, 0, 0, true, 7 ),
new Decimal(1230000000, 0, 0, true, 7 ),
-9999999999.9999999999m,
-9999999999.9999999999m };
// Define a set of integers to for decimals argument.
int[] decimals = { 1, 1, 4, 6, 8, 0, 3, 11, 9, 10};
Console.WriteLine("{0,26}{1,8}{2,26}",
"Argument", "Digits", "Result" );
Console.WriteLine("{0,26}{1,8}{2,26}",
"--------", "------", "------" );
for (int ctr = 0; ctr < values.Length; ctr++)
Console.WriteLine("{0,26}{1,8}{2,26}",
values[ctr], decimals[ctr],
Decimal.Round(values[ctr], decimals[ctr]));
}
}
// The example displays the following output:
// Argument Digits Result
// -------- ------ ------
// 1.45 1 1.4
// 1.55 1 1.6
// 123.456789 4 123.4568
// 123.456789 6 123.456789
// 123.456789 8 123.456789
// -123.456 0 -123
// -123.0000000 3 -123.000
// -123.0000000 11 -123.0000000
// -9999999999.9999999999 9 -10000000000.000000000
// -9999999999.9999999999 10 -9999999999.9999999999
"При округлении средних значений алгоритм округления выполняет тест равенства. Из-за проблем с двоичным представлением и точностью в формате с плавающей запятой значение, возвращаемое методом, может быть неожиданным".