57 votes

Imprécision de la décimale dans .NET

Hier, lors de débogage quelque chose d'étrange m'est arrivé et je ne peux pas vraiment l'expliquer:

Decimal calculation

Decimal calculations with brackets

Alors peut-être je ne suis pas voir l'évidence, ici, ou j'ai mal compris quelque chose à propos de décimales .NET, mais ne devrait pas les résultats seront-ils les mêmes?

Merci pour les réponses

71voto

Luaan Points 8934

decimal n'est pas magique, faire toutes les maths pour moi type. C'est toujours un nombre à virgule flottante - la principale différence de float , c'est que c'est un décimal à virgule flottante nombre, plutôt que binaire. Donc, vous pouvez facilement représenter 0.3 comme un nombre décimal (il est impossible qu'un nombre fini de nombres binaires), mais vous n'avez pas de précision infinie.

Cela rend le travail beaucoup plus proche d'un homme de faire les mêmes calculs, mais vous avez encore à imaginer quelqu'un qui fait de chaque opération individuelle. Il est conçu spécialement pour les calculs financiers, où vous ne faites pas le genre de chose que vous faites en Maths - vous simplement aller étape par étape, l'arrondissement chaque résultat en fonction jolie règles spécifiques.

En fait, pour de nombreux cas, decimal pourrait fonctionner bien pire que float (ou mieux, double). C'est parce qu' decimal ne fait pas arrondi automatique à tous. Faire de même avec double vous donne 22 comme prévu, parce que c'est automatiquement supposer que la différence n'a pas d'importance - en decimal, il n' - c'est l'un des points importants de la decimal. Vous pouvez émuler ce par l'insertion, manuel Math.Rounds, bien sûr, mais il ne fait pas beaucoup de sens.

30voto

Lưu Vĩnh Phúc Points 3183

Décimal ne peut stocker que des valeurs exactement représentables en décimal. Ici 22/24 = 0.91666666666666666666666 ... qui nécessite une précision infinie ou un type rationnel à stocker, qui n’est plus égal à 22/24 après arrondi. Si vous faites d'abord la multiplication, toutes les valeurs sont exactement représentables, d'où le résultat que vous voyez.

13voto

Sayse Points 9275

En ajoutant des crochets, vous vous assurez que la division est calculée avant la multiplication. Cela semble suffire à affecter suffisamment le calcul pour introduire un problème de précision flottante .

Étant donné que les ordinateurs ne peuvent pas produire tous les nombres possibles, vous devez en tenir compte dans vos calculs.

1voto

supercat Points 25534

Alors qu' Decimal a un degré de précision plus élevé que Double, sa principale caractéristique utile est que chaque valeur correspond exactement à celle de sa représentation explicite. Alors que le fixe de décimales types qui sont disponibles dans certaines langues peuvent garantir que ni l'addition ou la soustraction de deux correspondants de précision en virgule fixe les valeurs, ni la multiplication d'un point fixe de type par un nombre entier, ne sera jamais la cause de l'erreur d'arrondi, et tout en "big-virgule" de types tels que ceux trouvés dans Java peut garantir qu'aucun de multiplication sera toujours provoquer des erreurs d'arrondi, à virgule flottante Decimal des types comme celui qui se trouve dans .NET offre pas de telles garanties, et pas de virgule types peuvent garantir que la division des opérations peut être réalisé sans les erreurs d'arrondi (Java a la possibilité de lever une exception en cas d'arrondi serait nécessaire).

Tandis que ceux qui décident de faire Decimal être une variable de type point peut avoir eu l'intention qu'il soit utilisable soit pour les situations nécessitant plus de chiffres à droite du point décimal ou plus à gauche, les types à virgule flottante, que ce soit en base 10 ou en base 2, faire l'arrondi inévitable pour toutes les opérations.

-3voto

Gustav Points 3302

Vos expressions ne sont pas égales car la séquence des facteurs change et les facteurs sont exécutés dans cette séquence:

 Decimal d0 = 24m * 22m / 24m;
Decimal d1 = 22m / 24m * 24m;

Console.WriteLine(d0.ToString());
Console.WriteLine(d1.ToString());
 

Résultat:

 22
22.000000000000000000000000001
 

Les modifications apportées aux résultats sont expliquées en détail dans les autres réponses et commentaires.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X