如何舍入到最接近的偶数整数?

时间:2018-09-04 11:42:32

标签: c# algorithm math rounding

我的最后一个目标总是四舍五入到最接近偶数

例如,我要作为结果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(因为最接近的整数是1123,但它是 odd ,并且1122比<{{1 }})
  • 1124下一个偶数值,下一个更高偶数值)

我只使用正数

以此类推。

有些方法可以做到这一点,或者我应该实现自己的方法?

5 个答案:

答案 0 :(得分:64)

尝试此操作(让Math.RoundMidpointRounding.AwayFromZero一起使用,以获得“ next 偶数”,但已缩放-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

答案 1 :(得分:7)

一个班轮:

double RoundToNearestEven(double value) =>
    Math.Truncate(value) + Math.Truncate(value) % 2;

Fiddle

说明:如果我们在浮点数后有一个偶数且有一些数字,我们只需要除去这些数字即可。如果我们有奇数,则需要执行相同的操作,然后移至保证为偶数的下一个整数。

P.S。感谢@DmitryBychenko指出,将双倍转换为长距离并不是最明智的选择。

答案 2 :(得分: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;
    }

答案 3 :(得分:0)

这是我在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

“在对中点值进行四舍五入时,四舍五入算法将执行相等性测试。由于二进制表示形式和浮点格式的精度问题,该方法返回的值可能是意外的。”

答案 4 :(得分:0)

@马克 您的代码段与Excel计算不匹配。 在Excel中,尝试以下值:

  • 210.61-> 212
  • 2.98-> 4
  • -2,98-> -4

    使用您的代码:

  • 210.61-> 210
  • 2.98-> 2
  • -2,98-> -4

我修改了代码,现在可以正常工作:

public static double round_up_to_even(double number_to_round)
{
    var converted_to_int = Convert.ToDouble(number_to_round);
    if (converted_to_int %2 == 0) return Math.Round(converted_to_int, 0);

    var difference = (converted_to_int + 1) - number_to_round;
    if (difference <= 0.5) return Math.Round(converted_to_int + 1, 0);

    var vOffset=converted_to_int < 0 ? -1 : 1;
    return Math.Round(converted_to_int + vOffset, 0);
}