web-dev-qa-db-fra.com

Comment arrondir au nombre entier pair le plus proche?

Mon dernier objectif est toujours d'arrondir au l'entier pair le plus proche.

Par exemple, le nombre 1122.5196 Je veux comme résultat 1122. J'ai essayé ces options:

Math.Round(1122.5196d, 0, MidpointRounding.ToEven);       // result 1123
Math.Round(1122.5196d, 0, MidpointRounding.AwayFromZero); // result 1123

À la fin, ce que je voudrais obtenir, c’est toujours le entier le plus proche. Par exemple:

  • 1122.51 --> 1122
  • 1122.9 --> 1122 (parce que l'int plus proche est 1123 mais c'est impair, et 1122 est plus proche que 1124)
  • 1123.0 --> 1124 (le valeur paire suivante, la prochaine valeur plus élevée paire)

Je travaille uniquement avec nombres positifs.

Etc.

Il y a une méthode qui fait cela ou je devrais mettre en œuvre ma propre méthode?

43
Álvaro García

Essayez ceci (utilisons Math.Round avec MidpointRounding.AwayFromZero afin d'obtenir "next même valeur" mais mis à l'échelle - 2 facteur):

double source = 1123.0;

// 1124.0
double result = Math.Round(source / 2, MidpointRounding.AwayFromZero) * 2;

Démo:

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);

Résultat:

   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

Bon mot:

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

violon

Explication: si nous avons un nombre pair avec quelques chiffres après la virgule flottante, nous devons simplement nous débarrasser de ces chiffres. Si nous avons un nombre impair, nous devons faire la même chose et passer ensuite au nombre entier suivant qui est garanti égal.

P.S. Merci à @DmitryBychenko de nous avoir fait remarquer que l'idée de lancer du double au long n'est pas l'idée la plus brillante.

7
Dmitry Korolev

La raison pour laquelle vous obtenez le résultat 1123 même en utilisant

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

c’est parce que c’est exactement ce que vous avez demandé au compilateur de faire. Lorsque vous arrondissez à pair avec des décimales, n'oubliez pas que 1123.0 est pair.

c'est à dire. 1122.51 arrondi à même devient 1123.0 (notez que, comme il s’agit d’une décimale, il conservera toujours sa décimale et que, par conséquent, .0 en fait un nombre pair).

Au lieu de cela, j'écrirais une fonction pour faire ceci, quelque chose comme:

   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

Voici un exemple de fonction trouvée sur msdn, qui ne produira que les nombres les plus proches, semble bien correspondre à votre cas,

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

"Lors de l'arrondi des valeurs médianes, l'algorithme d'arrondi effectue un test d'égalité. En raison de problèmes de représentation binaire et de précision dans le format à virgule flottante, la valeur renvoyée par la méthode peut être inattendue."

0
Wesam