Pourquoi .NET utilise-t-il l'arrondi bancaire par défaut?

271

Selon la documentation, la decimal.Roundméthode utilise un algorithme d'arrondi à égal qui n'est pas courant pour la plupart des applications. Donc je finis toujours par écrire une fonction personnalisée pour faire l'algorithme arrondi plus naturel:

public static decimal RoundHalfUp(this decimal d, int decimals)
{
    if (decimals < 0)
    {
        throw new ArgumentException("The decimals must be non-negative", 
            "decimals");
    }

    decimal multiplier = (decimal)Math.Pow(10, decimals);
    decimal number = d * multiplier;

    if (decimal.Truncate(number) < number)
    {
        number += 0.5m;
    }
    return decimal.Round(number) / multiplier;
}

Quelqu'un connaît-il la raison de cette décision de conception du cadre?

Existe-t-il une implémentation intégrée de l'algorithme demi-tour dans le cadre? Ou peut-être une API Windows non gérée?

Il pourrait être trompeur pour les débutants qui écrivent simplement en decimal.Round(2.5m, 0)s'attendant à 3, mais en obtenant 2 à la place.

Darin Dimitrov
la source
105
Arrondir n'est pas «plus naturel». La nature n'y est pour rien. C'est tout simplement ce que vous avez appris à l'école primaire lorsque vous avez appris le concept «d'arrondi». Les leçons de l'école secondaire ne brossent pas toujours un tableau complet.
Rob Kennedy
45
@Rob Et c'est pourquoi c'est plus naturel , même si ce n'est pas correct
Pacerier
10
Je ne comprends pas, @Pacerier. Je lui ai expliqué pourquoi il est pas naturel, et vous dites que est en fait pourquoi il est naturel. Comment mon argument fonctionne-t-il contre ma conclusion, qui est l'opposé de la vôtre? Les choses auxquelles vous vous êtes habitué peuvent sembler naturelles, et parfois nous disons au sens figuré que quelque chose est une «seconde nature», mais cela ne les rend pas naturelles.
Rob Kennedy
16
@Rob Je dis que c'est naturel, parce que c'est naturel. Vous ne savez qu'il ya 36 objets différents avec le même nom de la variable naturelle droite?
Pacerier
9
c'est certainement l'analogue de la nature, donc c'est le mauvais mot à utiliser; mais cela est pédant. Peut-être que "d'habitude" serait un meilleur mot à utiliser .. "quel est l'arrondi habituel que les gens font"> 0,5 passe à 1,0
pourquoi

Réponses:

196

Probablement parce que c'est un meilleur algorithme. Au cours de nombreux arrondis effectués, vous aurez la moyenne que tous les 0,5 finissent par arrondir également de haut en bas. Cela donne de meilleures estimations des résultats réels si vous êtes, par exemple, en ajoutant un tas de nombres arrondis. Je dirais que même si ce n'est pas ce à quoi certains peuvent s'attendre, c'est probablement la chose la plus correcte à faire.

Kibbee
la source
71
en supposant que vous ayez une distribution plate des entrées impaires et paires bien sûr
jk.
7
+1 pour un meilleur algorithme , bien qu'Ostemar ait la réponse réelle ( stackoverflow.com/questions/311696/… )
Ian Boyd
2
@Ian, je donne également cette réponse +1. Quoi qu'il en soit, nous pouvons obtenir la «réponse acceptée déplacée» Peut-être que le PO peut le faire. La vraie réponse à "pourquoi" il utilise cette méthode est à mi-chemin de la page. Bien que j'aime beaucoup le boost de reps, je reçois environ une fois par semaine de cette réponse.
Kibbee
@Kibbee - merci d'avoir poussé ma réponse. Je suppose que c'est au PO de changer la réponse acceptée comme il l'entend?
Ostemar
-1 pour dire que c'est un meilleur algorithme. - Étant donné un échantillon aléatoire de nombres en utilisant l'arrondi bancaire, vous finirez par avoir plus de nombres aux positions paires qu'aux positions impaires. - Ce n'est qu'après avoir fait la moyenne de ces chiffres que vous obtenez à nouveau un écart similaire à la distribution d'origine. - Cependant, si vous traciez par exemple ces données dans un nuage de points, vous pourriez voir un regroupement artificiel.
paul23
437

Les autres réponses avec les raisons pour lesquelles l'algorithme du banquier (aka demi-rond à égal ) est un bon choix sont tout à fait correctes. Il ne souffre pas autant de biais négatif ou positif que la méthode arrondie à moitié de zéro sur la plupart des distributions raisonnables.

Mais la question était de savoir pourquoi .NET utilise l'arrondi réel de Banker par défaut - et la réponse est que Microsoft a suivi la norme IEEE 754 . Cela est également mentionné dans MSDN for Math.Round sous Remarques.

Notez également que .NET prend en charge la méthode alternative spécifiée par IEEE en fournissant l' MidpointRoundingénumération. Ils auraient bien sûr pu fournir plus d'alternatives à la résolution des liens, mais ils choisissent simplement de respecter la norme IEEE.

Ostemar
la source
17
Alors, pourquoi IEEE 754 suit-il l'arrondi des banquiers? Cette réponse (toujours bonne) passe juste le seau.
Henk Holterman
4
@HenkHolterman Probablement à cause de ce qui est mentionné dans les autres réponses (et comme je l'ai résumé); il ne souffre pas (trop) d'un biais négatif ou positif et en tant que tel, il constitue un défaut plus résonable pour la plupart des distributions et des domaines problématiques.
Ostemar
Je pense que c'est intéressant parce que IEEE 754 est la norme pour les nombres à virgule flottante dont Decimal n'est pas. Peut-être qu'il suit IEEE 754 afin que le même algorithme soit utilisé pour arrondir le double en décimal.
Brandon Barkley
1
@BrandonBarkley Un nombre décimal ou décimal est un nombre à virgule flottante, et IEEE 754 inclut des nombres à virgule flottante décimaux .
Pablo H
88

Bien que je ne puisse pas répondre à la question «Pourquoi les concepteurs de Microsoft ont-ils choisi cette option par défaut?», Je veux juste souligner qu'une fonction supplémentaire n'est pas nécessaire.

Math.Roundvous permet de spécifier un MidpointRounding:

  • ToEven - Lorsqu'un nombre est à mi-chemin entre deux autres, il est arrondi vers le nombre pair le plus proche.
  • AwayFromZero - Lorsqu'un nombre est à mi-chemin entre deux autres, il est arrondi vers le nombre le plus proche qui est loin de zéro.
Michael Stum
la source
8
Et comme je l'ai mentionné dans les discussions connexes, assurez-vous que vous êtes cohérent dans votre arrondi - si vous effectuez parfois des arrondis dans la base de données, et parfois dans .net, vous aurez d'étranges erreurs d'un cent qui vous prendront des semaines pour comprendre.
chris
59
Une fois, un client m'a payé plus de 40 000 $ pour retrouver une erreur d'arrondi de 0,11 $ entre deux chiffres qui étaient tous deux à peine d'un milliard de dollars; le 0,11 $ était dû à une différence dans l'erreur d'arrondi au 8e chiffre entre un ordinateur central et SQL Server. Parlez d'un perfectionniste!
EJ Brennan
12
@EJB - je serais probablement un perfectionniste si j'avais affaire à un milliard de dollars ;-)
royse41
12
@EJ Brennan: Il vous a fallu 40 000 $ pour comprendre cela? Je vois des problèmes comme celui-ci tout le temps, l'arrondi est la cause n ° 1, la normalisation double / flottante est la cause n ° 2, l'erreur de programmation n ° 3 - n ° 3 peut être immédiatement définie sur n ° 1 s'il n'y a pas de cas de test prédéfinis. btw pouvez-vous s'il vous plaît me mettre en contact avec votre client billionare, je pense que je pourrais aussi trouver quelques bugs de plus de 40k $ dans son système! : D
3
@seanxe: Ou si vous aviez vu Office Space. Sérieusement, chaque fois que vous voyez de minuscules inexactitudes mystérieuses dans l'argent, résoudre le mystère de la façon exacte dont elles se produisent est presque toujours une bonne idée. Il est possible que vous décidiez de ne pas corriger les bogues, mais connaître la cause sous-jacente a toujours de la valeur. Je parie que de nombreuses personnes qui travaillent avec de l'argent sont heureuses de constater même de minuscules inexactitudes.
Brian
22

Les décimales sont principalement utilisées pour l' argent ; l'arrondissement bancaire est courant lorsque l'on travaille avec de l' argent . Ou vous pourriez dire.

Ce sont surtout les banquiers qui ont besoin du type décimal; il fait donc «l'arrondissement bancaire»

L'arrondi bancaire a l'avantage qu'en moyenne vous obtiendrez le même résultat si vous:

  • arrondir un ensemble de «lignes de facture» avant de les additionner,
  • ou ajoutez-les puis arrondissez le total

L'arrondi avant l'addition a permis d'économiser beaucoup de travail les jours précédant les ordinateurs.

(Au Royaume-Uni, lorsque nous sommes allés aux banques décimales, les demi-pence ne pouvaient pas être traitées, mais pendant de nombreuses années, il restait une pièce de demi-pence et le magasin avait souvent des prix se terminant en demi-pence - donc beaucoup d'arrondis)

Ian Ringrose
la source
8
"Les décimales sont surtout utilisées pour l'argent" ... et tout le reste qui n'est pas un entier.
John Tyree,
3
@JohnTyree, Pas vrai la plupart du temps un double / float est utilisé quand ce n'est pas un entier. voir stackoverflow.com/questions/2545567/…
Ian Ringrose
3
Sensationnel. Erreur ridicule de ma part. Decmialoui. Décimales, non. Pour la postérité, je suis d'accord avec le sentiment d'origine ici.
John Tyree
Les banquiers peuvent aimer l'arrondi des banquiers, mais les comptables ne sont peut-être pas fans de cela, ils disent que la différence de 0,005 devrait arrondir à 0,01, sans dépendre du nombre impair ou pair.
JustAMartin
0

Utilisez une autre surcharge de la fonction Round comme celle-ci:

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)

Il affichera 3 . Et si vous utilisez

decimal.Round(2.5m, 0,MidpointRounding.ToEven)

vous obtiendrez l'arrondissement bancaire.

Omid Sadeghi
la source
4
Cela ne répond pas à la question de savoir pourquoi l'arrondi bancaire a été choisi par défaut.
shortstuffsushi