Que faire? Est-ce que quelqu'un connaît une méthode d'arrondi sans ces bugs? P> maths.round (8.075, 2, midspointrounding.awayfromzero) code> renvoie
8.07 code>, bien qu'il puisse retourner
8.08 code>. Mystérieusement assez,
7.075 code> fonctionne bien, mais
9.075 code> renvoie également
9.07 code>! P>!
3 Réponses :
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
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
Si vous comptez avec 10 doigts, comme les humains, vous n'avez aucune difficulté à exprimer la valeur décimale 8.075 précisément: mais les ordinateurs comptent avec 2 doigts, ils ont besoin d'exprimer cette valeur en pouvoirs de 2: p> 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)
C'est pourquoi réel i> mathématiciens compter en utilisant 60 doigts .
La solution possible peut être:
(double)Math.Round((decimal)8.075, 2, MidpointRounding.AwayFromZero);
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) Code>
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 i>, 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 i>. 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 i>. 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.