Arrondi à l'ensemble dans .NET

Tous barbus ku, camarades!

Nous savons tous ce qu'est l'arrondi. Si quelqu'un a oublié, l'arrondi est le remplacement d'un nombre avec sa valeur approximative, écrit avec moins de chiffres significatifs. Si vous demandez à une personne à la volée ce qui se passe lorsque vous arrondissez 6,5 à des nombres entiers, elle répondra «7» sans hésitation. L'école nous a appris que les nombres sont arrondis à l'entier le plus proche, qui est plus grand en valeur absolue. Autrement dit, si dans le nombre arrondi la partie fractionnaire est égale ou supérieure à la moitié de la décharge de la partie entière, alors nous arrondissons le nombre d'origine à la plus grande plus proche.

Autrement dit:
6,4 = 6 6,5 = 7 6,6 = 7 
etc.

Et donc, en quittant l'école et en devenant programmeurs, nous attendons souvent le même comportement de nos puissants langages de programmation. Oubliant complètement qu'à l'école on nous a enseigné «l'arrondi mathématique», mais en fait il y a beaucoup plus de types d'arrondi. Sur Wikipedia uniquement, vous pouvez creuser le nombre d'options d'arrondi de 0,5 à l'entier le plus proche:

  • Arrondi mathématique
  • Arrondi aléatoire
  • Arrondi alterné
  • Arrondi bancaire

Le premier type, «l'arrondissement mathématique», nous avons tous appris de l'école. Vous pouvez lire sur les deuxième et troisième types à votre guise, ils ne m'intéressent pas dans cet article aujourd'hui.

Mais «l'arrondi bancaire» est déjà intéressant. "Pourquoi?" - demandez-vous. Dans le sous-réseau, nous utilisons souvent la classe Convert , qui fournit de nombreuses méthodes pour convertir un type de données en un autre (à ne pas confondre avec le cast, elle sera décrite ci-dessous). Et maintenant, il s'avère que lors de la conversion de nombres à virgule flottante ( double, flottant, décimal ) en un type entier entier via la méthode Convert.ToInt32, l' arrondi «bancaire» fonctionne sous le capot. Il est utilisé ici par défaut!

Et il semble que l'ignorance de cette bagatelle n'affecte pas grandement votre travail, mais dès que vous devrez travailler avec des statistiques et des indicateurs de calcul basés sur un tas de toutes sortes d'enregistrements et de chiffres, cette chose sortira latéralement. Parce que nous nous attendons (par ignorance) à ce que toutes nos conversions / arrondis dans les calculs fonctionnent selon les règles d'arrondis "mathématiques". Et nous ressemblons à un bélier sur une nouvelle porte pour le résultat de l'arrondi 6.5 , qui est 6 .

La première pensée du programmeur qui voit cela est: "Peut-être que l'arrondi fonctionne dans la direction opposée, et selon les règles, il arrondit au plus petit nombre?", "Peut-être que j'ai oublié quelque chose des mathématiques de l'école?". Puis il va sur Google et comprend qu'ils n'ont rien oublié et qu'une sorte de mob se poursuit. À cette étape, le développeur paresseux décidera qu'il s'agit du comportement standard de la méthode Convert.ToInt32 , arrondi au plus petit entier et notant pour une recherche ultérieure. Et il pensera que si Convert.ToInt32 (6,5) = 6 , alors par analogie Convert.ToInt32 (7,5) = 7 . Mais ça y était. À l'avenir, ces développeurs seront frappés à la tête avec un tas de bugs du département QA.

Le fait est que l'arrondi «bancaire» fonctionne un peu plus délicat - il arrondit un nombre à l'entier pair le plus proche, et non au module entier le plus proche. Ce type d'arrondi est censé être plus honnête en cas d'application dans les opérations bancaires - les banques ne se priveront pas ni ne se priveront des clients, en supposant qu'il y a autant d'opérations avec une partie entière paire qu'il y a d'opérations avec une partie entière impaire. Mais pour moi - ce n'est pas encore clair :) C'est pourquoi Convert.ToInt32 (6.5) donnera un résultat de 6 , et le résultat de Convert.ToInt32 (7.5) sera 8 , pas 7 :)

Que faire pour que tout le monde connaisse l'arrondi «mathématique»? Les méthodes de classe Convert n'ont pas d'options d'arrondi supplémentaires. C'est vrai, car cette classe sert principalement non pas à l'arrondi, mais à la conversion de type. La merveilleuse classe de Math avec sa méthode Round vient à la rescousse. Mais ici aussi soyez prudent, car par défaut cette méthode fonctionne de la même manière que l'arrondi dans Convert.ToInt32 () - selon la règle "bancaire". Toutefois, ce comportement peut être modifié à l'aide du deuxième argument, qui fait partie de la méthode Round . Ainsi, Math.Round (someNumber, MidpointRounding.ToEven ) nous donnera l'arrondi "bancaire" par défaut. Mais Math.Round (someNumber, MidpointRounding.AwayFromZero ) fonctionnera selon les règles habituelles d'arrondi "mathématique".

Et d'ailleurs, Convert.ToInt32 () n'utilise pas System.Math.Round () sous le capot. Le déterrage particulier de la mise en œuvre de cette méthode sur github - arrondi est envisagé en fonction des résidus:

 public static int ToInt32(double value) { if (value >= 0) { if (value < 2147483647.5) { int result = (int)value; double dif = value - result; if (dif > 0.5 || dif == 0.5 && (result & 1) != 0) result++; return result; } } else { if (value >= -2147483648.5) { int result = (int)value; double dif = value - result; if (dif < -0.5 || dif == -0.5 && (result & 1) != 0) result--; return result; } } throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); } 

Et enfin, quelques mots sur le casting de caractères :

 var number = 6.9; var intNumber = (int)number; 

Dans cet exemple, j'ai converti un type à virgule flottante ( double dans ce cas) en un entier entier. Ainsi, lors de la conversion en types entiers, la partie non entière entière est simplement tronquée . Par conséquent, dans cet exemple, la variable " intNumber " contiendra le nombre 6 . Il n'y a pas de règles d'arrondi ici, juste couper tout ce qui vient après le point décimal. N'oubliez pas cela!

Liens connexes:


PS Merci à Maxim Yakushkin d'avoir attiré l'attention sur ce moment implicite.

PPS Soit dit en passant, en python, l' arrondi par défaut fonctionne de la même manière sur une base «bancaire». Peut-être que la même chose est dans votre langue, faites attention aux chiffres :)

Source: https://habr.com/ru/post/fr462299/


All Articles