8
votes

Bug Math.Round - Que faire?

maths.round (8.075, 2, midspointrounding.awayfromzero) renvoie 8.07 , bien qu'il puisse retourner 8.08 . Mystérieusement assez, 7.075 fonctionne bien, mais 9.075 renvoie également 9.07 ! !

Que faire? Est-ce que quelqu'un connaît une méthode d'arrondi sans ces bugs?


5 commentaires

Je suis très douteux .net aurait de tels insectes, si c'est ce qui se passe alors je suis sûr que cela a été mis en œuvre de cette façon pour une raison.


Vous pouvez utiliser un type décimal car ils sont plus précis: Math.Round (8.075m, 2, MidspointRounding.awayFromzero)


Nous avons besoin de jon skeet ici


Ahh, j'ai oublié de mentionner que Eric Lippert vient d'écrire un excellent article de blog sur l'arrondi: ericlippert.com/2013/05/16/spot-the-defect-rounding-part-two


@Jasd: Ce n'est pas que les décimales sont plus précises , bien qu'ils soient. Il est que les décimales ont une erreur de représentation zéro si la quantité souhaitée est une fraction avec des pouvoirs de cinq et deux dans le dénominateur . Les doubles ont une erreur de représentation zéro si la quantité souhaitée est une fraction avec des pouvoirs de deux dans le dénominateur . Comme 8075/1000 a une puissance de 5 dans le dénominateur, même dans les termes les plus bas, il reçoit une erreur de représentation dans un double.


3 Réponses :


5
votes

Je ne suis pas un spécialiste .NET, mais ces chiffres ne peuvent pas être exactement représentés comme doubles, l'arrondi est donc précis si vous prenez en compte la valeur réelle de ces 3 numéros:

7.075 ==> 7.07500000000000017763568394002504646778106689453125
8.075 ==> 8.074999999999999289457264239899814128875732421875
9.075 ==> 9.074999999999999289457264239899814128875732421875


3 commentaires

Comment avez-vous trouvé les vraies valeurs?


@Ashburlaczenko avec un programme Java, mais je suppose que vous pouvez faire la même chose dans .NET.


@Ashburlaczenko: J'ai un programme C # pour cela ici: blogs.msdn.com/b/ericlippert/archive/2011/02/17/... et un message de suivi récent ici: ericlippert.com/2013/05/13/spot-the-defect-rounding



12
votes

Si vous comptez avec 10 doigts, comme les humains, vous n'avez aucune difficulté à exprimer la valeur décimale 8.075 précisément: xxx pré>

mais les ordinateurs comptent avec 2 doigts, ils ont besoin d'exprimer cette valeur en pouvoirs de 2: p> xxx pré>

J'ai abandonné avec la crampe des doigts en tapant les termes, mais le point est que peu importe le nombre de pouvoirs de 2 que vous ajoutez, vous allez jamais em> obtenir exactement 8.075m. Un problème similaire à la façon dont les humains ne peuvent jamais écrire le résultat de 10/3 précisément, il a un nombre infini de chiffres dans la fraction. Vous ne pouvez écrire que le résultat de cette expression avec précision lorsque vous comptez avec 6 doigts. P>

Un processeur bien sûr n'a pas assez de stockage pour stocker un nombre infini de bits pour représenter une valeur. Donc, ils doivent em> tronquer la séquence du chiffre, une valeur de type double peut stocker 53 bits. P>

En conséquence, la valeur décimale 8.075 est arrondi lorsqu'il est stocké dans le processeur. La séquence de 53 bits, reconverti en décimal, est la valeur ~ 8.0749999999999999289. Pour qui, comme prévu, est arrondi au 8.07 par votre code. P>

Si vous voulez 10 résultats mathématiques, vous devez utiliser un type de données qui stocke des numéros dans la base 10. C'est le système.Decimal Tapez .net. Correction: P>

decimal result = Math.Round(8.075m, 2, MidpointRounding.AwayFromZero)


1 commentaires

C'est pourquoi réel mathématiciens compter en utilisant 60 doigts .



-2
votes

La solution possible peut être:

(double)Math.Round((decimal)8.075, 2, MidpointRounding.AwayFromZero);


0 commentaires