2010-02-06 9 views
7

Possible en double:
Why is floating point arithmetic in C# imprecise?résultat étrange lorsque vous soustrayez double

Je traite avec quelques chiffres et C#, et la ligne suivante des résultats de code dans un autre numéro que l'on pourrait attendre:

double num = (3600.2 - 3600.0); 

Je m'attendais num à 0,2, mais il s'est avéré être 0,19999999999998181. Y a-t-il une raison pour laquelle elle produit une décimale proche, mais différente?

+0

Huh, même ici. Pas votre machine. – tsilb

+2

http://stackoverflow.com/questions/1498296/net-problem-with-subtracting-double-values ​​ –

+2

http://stackoverflow.com/questions/753948/why-is-floating-point-arithmetic-in-c -imprecise –

Répondre

10

Ceci est dû au fait que double est un type de données en virgule flottante.

Si vous souhaitez une meilleure précision, vous pouvez utiliser decimal à la place.

Le suffixe littéral pour decimal est m, donc à utiliser decimal arithmétique (et produire un résultat decimal) vous pouvez écrire votre code comme

var num = (3600.2m - 3600.0m); 

Notez qu'il ya des inconvénients à l'aide d'un decimal. C'est un type de données de 128 bits par opposition à 64 bits qui est la taille d'un double. Cela le rend plus cher à la fois en termes de mémoire et de traitement. Il a également une gamme beaucoup plus petite que double.

+2

Cela n'a rien avec la précision que vous avez (sauf si vous avez une précision infinie bien sûr). C'est la conversion d'une base à l'autre qui crée ceci. – AraK

+6

Quand la désinformation sur les types IEEE 754 s'arrêtera-t-elle? Ce n'est pas un type imprécis! C'est un type exact, mais il ne peut représenter qu'une gamme limitée de nombres. Tous les nombres non représentés exactement sont approximés, et ceci est la cause des erreurs. Si vous voulez exprimer uniquement des puissances de deux, dans la plage du type, vous ne perdrez jamais de précision avec un point flottant. – codekaizen

+1

@AdamRalph - c'est faux aussi à propos de Decimal. System.Decimal est un type à virgule flottante, mais il est en base 10, donc la base habituelle 10 arithmatique s'applique. Essayez de calculer avec 1/3, cependant, et Decimal perdra de la précision, bien qu'avec la mantisse de 96 bits, ce sera une perte beaucoup plus petite que System.Double. – codekaizen

0

Changer votre type de decimal:

decimal num = (3600.2m - 3600.0m); 

Vous devriez également lire this.

1

Il y a une raison.

La raison en est que la façon dont le numéro est stocké en mémoire, dans le cas du type de données double, ne permet pas une représentation exacte du nombre 3600.2. Cela ne permet pas non plus une représentation exacte du nombre 0.2.

0.2 a une représentation infinie en binaire. Si vous voulez le stocker dans la mémoire ou les registres du processeur, pour effectuer quelques calculs, un nombre proche de 0.2 avec une représentation finie est stocké à la place. Il peut ne pas être apparent si vous exécutez du code comme celui-ci.

double num = (0.2 - 0.0); 

En effet, dans ce cas, tous les chiffres binaires disponibles pour représenter les nombres en deux types de données sont utilisées pour représenter la partie décimale du nombre (il n'y a que la partie décimale) et la précision est plus élevé. Si vous stockez le nombre 3600.2 dans un objet de type double, certains chiffres sont utilisés pour représenter la partie entière - 3600 et il y a moins de chiffres représentant la partie fractionnaire. La précision est plus faible et la partie fractionnaire qui est en fait stockée dans la mémoire diffère de 0.2 assez, qu'elle devient apparente après la conversion du double en chaîne