web-dev-qa-db-ja.com

最も近い偶数の整数に丸める方法は?

私の最後の目標は、常に最も近い偶数の整数に丸めることです。

たとえば、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ですが、oddであり、1122nearer1124よりも大きいため)
  • 1123.0 --> 1124次の偶数値、次のより高い偶数値)

正の数でのみ動作します。

等々。

それを行う方法はいくつかありますか、独自の方法を実装する必要がありますか?

43
Álvaro García

これを試してください(「next偶数値」を取得するためにMath.RoundMidpointRounding.AwayFromZeroを使用しますが、scaled-2 factor):

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
64
Dmitry Bychenko

一発ギャグ:

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

フィドル

説明:浮動小数点の後にいくつかの数字がある偶数がある場合、それらの数字を取り除く必要があります。奇数がある場合、同じことをしてから、偶数であることが保証されている次の整数に移動する必要があります。

追伸@DmitryBychenkoに、ダブルキャストからロングキャストまでが最も賢明なアイデアではないことを指摘してくれてありがとう。

7
Dmitry Korolev

使用しても結果が1123になる理由

Math.Round(1122.5196d, 0, MidpointRounding.ToEven);

それはまさにあなたがコンパイラーに行うように頼んだことだからです。小数で偶数に丸める場合、1123.0は偶数であることを忘れないでください。

すなわち。偶数に丸められた1122.51は1123.0になります(10進数であるため、常に小数点以下の桁が保持されるため、ここで.0を指定すると偶数になります)。

代わりに、これを行う関数を作成しますsomething like:

   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
Mark

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

「中間点の値を丸めるとき、丸めアルゴリズムは等価性テストを実行します。浮動小数点形式のバイナリ表現と精度の問題のため、メソッドによって返される値は予期しないものになる可能性があります。」

0
Wesam