10
votes

Résultat étrange lors de la soustraction des doubles

Duplicaté possible:

Pourquoi le point flottant est-il arithmétique en C # imprécise?

J'ai géré certains chiffres et C # et que la ligne de code suivante entraîne un numéro différent de celui-ci. Cependant, cependant, il s'est avéré être 0.19999999999998181. Y a-t-il une raison pour laquelle il produit une décimale proche, mais toujours différente?


5 commentaires

Hein, même ici. Pas votre machine.


Stackoverflow.com/questions/1498296/... < / a>


Stackoverflow.com/ Questions / 753948 / ...


Chaque jour quand un débutant poser cette question, un petit morceau de moi meurt à l'intérieur ...


@Leppie - Bientôt, nous manquerons sûrement!


4 Réponses :


11
votes

Ceci est parce que double code> est un type de données de point flottant.

Si vous souhaitez une plus grande précision, vous pouvez passer à l'utilisation de décimal code>. p>

P> P> Le suffixe littéral pour décimal code> est m, de manière à utiliser décimal code> arithmétique (et produire un décimal code> résultat) Vous pouvez écrire votre code comme p >

var num = (3600.2m - 3600.0m);


13 commentaires

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


Quand la Misinformate à propos de IEEE 754 Types s'arrête-t-elle? C'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 chiffres non représentés sont approchés exactement, et c'est la cause des erreurs. Si vous souhaitez exprimer uniquement les pouvoirs de deux, dans la plage de type, vous ne perdrez jamais de précision avec un point flottant.


@Adamralph - c'est faux sur la décimale, aussi. System.Decimal est un type de point flottant, mais il est à la base 10, la base de la base 10 habituelle que l'arithmatic s'applique. Essayez de calculer avec 1/3, cependant, et la décimale perdra exactement la précision, bien que la Mantissa 96 bits, ce sera une perte beaucoup plus petite que System.Double.


Bien, je vais supprimer «imprécise» de la réponse. C'est l'effet que je démontrais plutôt que la cause sous-jacente


@CODAIZEN - Certes, je n'ai pas examiné cela dans des détails fins, mais je ne suis pas sûr de votre affirmation selon laquelle System.Decimal est un type de point flottant. de la première ligne de l'entrée MSDN du type - "Le mot clé décimal indique un type de données de 128 bits. Comparé aux types de points flottants, le type décimal a une plus grande précision et une gamme plus petite" - cela implique que ce n'est pas un Type de point flottant


@Adamralph - Je ne sais pas combien de fois j'ai eu cet argument avec d'autres devs. ;) Vous devez lire davantage sur ... "Un nombre décimal est une valeur à virgule flottante qui consiste en un signe, une valeur numérique où chaque chiffre de la valeur varie de 0 à 9, et un facteur d'échelle qui indique la position d'un point décimal flottant qui sépare les parties intégrale et fractionnelle de la valeur numérique. " msdn.microsoft.com/en-us/library/system.decimal. Aspx


Notez que la confusion sur la décimale est généralement autour de la base ... J'étais confus à ce sujet aussi jusqu'à ce que je lisais les docs pour la 3ème fois. System.Single et System.Double sont Binary (base 2) Types de points flottants et System.Decimal est un Decimal (base 10) de type point flottant. Cela rend les calculs des pouvoirs de 10 exacts avec décimal, où ils sont approximatifs avec un seul et double.


@Adamalph, CodeCaizan est absolument correct. Une décimale a une .... point décimal, et comme la position de ce point décimal peut bouger (du lien MSDN ci-dessus ", la représentation binaire d'une valeur décimale consiste en un signe 1 bits, un nombre entier de 96 bits, et Un facteur de mise à l'échelle utilisée pour diviser l'entier 96 bits et spécifier quelle partie de celle-ci est une fraction décimale. Le facteur de mise à l'échelle est implicitement le nombre 10, élevé à un exposant allant de 0 à 28 "... C'est une décimale flottante.


Ok, je comprends ce que vous dites et j'accepte que décimal est un type de point de données à virgule flottante. Il semble que la ligne que j'ai citée de MSDN soit extrêmement trompeuse. Cependant, ma réponse (tout en étant nécessairement la meilleure réponse) tient toujours - je ne crois pas que cela indique quelque chose de faux. Dans sa forme actuelle, je ne vois pas pourquoi quiconque devrait ressentir la nécessité de descendre la réponse.


@Adamalph - Eh bien, initialement, c'était très trompeur et vous l'avez édité un peu. Il reste encore quelques problèmes avec cela actuellement, dans cette décimale étant 128 bits et double étant 64 est la raison pour laquelle la décimale est meilleure. Bien sûr, vous obtenez plus de précision avec le type décimal, mais ce n'est pas une solution parfaite (vous pouvez toujours avoir une erreur d'arrondi), et ce n'est pas strictement à cause du nombre de bits (la taille des questions importantes). Vous pouvez toujours avoir une erreur catastrophique de la soustrription, mais votre façon de présenter la décimale car la meilleure solution ne contient aucun avertissement à ce sujet.


@Adamralph - Je conviens que l'entrée MSDN pour le type est trompeuse. Il devrait dire "le mot clé décimal désigne un type de point de données BASE-10 BASE-10 Comparé à IEEE 754 Binary Binary Point Types, le type décimal a une plus grande précision et une gamme plus petite, mais peut toujours souffrir des mêmes erreurs de rond et d'annulation catastrophique lors de la soustraction de nombres presque égaux comme ses homologues binaires.


@CODAIZEN - J'ai mentionné que la décimale est de 128 bits par opposition à 64 bits sous la forme d'un désavantage par rapport à un double, plutôt que la raison d'être un meilleur choix. Je vais essayer de rendre cela plus clair.


@Adamalph - mais ce n'est pas un inconvénient strict, c'est le point. Et ce n'est pas nécessairement un avantage non plus. Vrai, dans ce cas particulier, cela rend le type plus précis, car il a 96 morceaux significatifs, mais il aurait pu avoir 124 morceaux d'exposant et 4 morceaux significatifs, puis même s'il aurait 128 morts ce ne serait pas être meilleur que le double. Unilatéralement déclarant que 128 bits sont meilleurs, voire que plus de précision est meilleure (elle n'implique pas strictement plus de précision), manque les nuances et perpétue le malentendu, des types de points flottants, raison pour laquelle j'ai bu.




0
votes

Changer votre type à Décimal CODE>:

decimal num = (3600.2m - 3600.0m);


0 commentaires

1
votes

Il y a une raison.

La raison est que la manière dont le nombre est stocké en mémoire, dans le cas du type de double données, ne permet pas une représentation exacte du nombre 3600.2. Cela ne permet également pas une représentation exacte du nombre 0.2. P>

0,2 a une représentation infinie en binaire. Si vous souhaitez la stocker en mémoire ou dans des registres de processeur, effectuez des calculs, un nombre proche de 0,2 avec une représentation finie est stocké à la place. Il peut ne pas être évident si vous exécutez du code comme celui-ci. P>

double num = (0.2 - 0.0);


0 commentaires