par exemple, avec le dollar, vous n'avez jamais une précision inférieure à 0,01 $
Oh vraiment?
le problème séculaire de la raison pour laquelle vous ne devriez pas stocker de devise sous forme de nombre à virgule flottante IEEE 754.
N'hésitez pas à stocker les pouces en nombres à virgule flottante IEEE 754 . Ils stockent précisément ce que vous attendez.
N'hésitez pas à stocker toute somme d'argent en nombres à virgule flottante IEEE 754 que vous pouvez stocker en utilisant les graduations qui divisent une règle en fractions de pouce.
Pourquoi? Parce que lorsque vous utilisez IEEE 754, c'est comme ça que vous le stockez.
Le problème avec les pouces, c'est qu'ils sont divisés en deux. La chose à propos de la plupart des types de devises est qu'elles sont divisées en dixièmes (certaines ne le sont pas, mais restons concentrés).
Cette différence ne serait pas si confuse, sauf que, pour la plupart des langages de programmation, l'entrée et la sortie des nombres à virgule flottante IEEE 754 sont exprimées en décimales! Ce qui est très étrange car ils ne sont pas stockés en décimales.
Pour cette raison, vous ne voyez jamais comment les bits font des choses étranges lorsque vous demandez à l'ordinateur de les stocker 0.1
. Vous ne voyez l'étrangeté que lorsque vous faites des calculs contre cela et il y a d'étranges erreurs.
De la java efficace de Josh Bloch :
System.out.println(1.03 - .42);
Produit 0.6100000000000001
Ce qui est le plus révélateur, ce n'est pas le 1
chemin assis là-bas à droite. Ce sont les chiffres étranges qui ont dû être utilisés pour l'obtenir. Plutôt que d'utiliser l'exemple le plus populaire 0.1
, nous devons utiliser un exemple qui montre le problème et évite l'arrondi qui le cacherait.
Par exemple, pourquoi cela fonctionne-t-il?
System.out.println(.01 - .02);
Produit -0.01
Parce que nous avons eu de la chance.
Je déteste les problèmes difficiles à diagnostiquer car j'ai parfois la «chance».
IEEE 754 ne peut tout simplement pas stocker 0,1 avec précision. Mais si vous lui demandez de stocker 0,1 puis de l'imprimer, il affichera 0,1 et vous penserez que tout va bien. Ce n'est pas bien, mais vous ne pouvez pas le voir car il est arrondi pour revenir à 0,1.
Certaines personnes confondent les autres en appelant ces écarts des erreurs d'arrondi. Non, ce ne sont pas des erreurs d'arrondi. L'arrondi consiste à faire ce qu'il est censé faire et à transformer ce qui n'est pas un nombre décimal en un nombre décimal afin qu'il puisse s'imprimer à l'écran.
Mais cela masque l'inadéquation entre la façon dont le numéro est affiché et la façon dont il est stocké. L'erreur ne s'est pas produite lors de l'arrondi. Cela s'est produit lorsque vous avez décidé de mettre un nombre dans un système qui ne peut pas le stocker avec précision et que vous avez supposé qu'il était stocké précisément quand il ne l'était pas.
Personne ne s'attend à ce que π soit stocké avec précision dans une calculatrice et ils parviennent à l'utiliser très bien. Le problème n'est donc même pas lié à la précision. Il s'agit de la précision attendue. Les ordinateurs affichent un dixième de 0.1
la même manière que nos calculatrices, nous nous attendons donc à ce qu'ils stockent un dixième parfaitement comme le font nos calculatrices. Ils ne le font pas. Ce qui est surprenant, car les ordinateurs sont plus chers.
Permettez-moi de vous montrer le décalage:
Notez que 1/2 et 0,5 s'alignent parfaitement. Mais 0,1 ne correspond tout simplement pas. Bien sûr, vous pouvez vous rapprocher si vous continuez à diviser par 2, mais vous ne le frapperez jamais exactement. Et nous avons besoin de plus en plus de bits chaque fois que nous divisons par 2. Donc, représenter 0,1 avec tout système qui divise par 2 a besoin d'un nombre infini de bits. Mon disque dur n'est pas si gros.
Donc , IEEE 754 cesse d' essayer quand il court en bits. Ce qui est bien car j'ai besoin de place sur mon disque dur pour ... des photos de famille. Pas vraiment. Photos de famille. : P
Quoi qu'il en soit, ce que vous tapez et ce que vous voyez sont les décimales (à droite) mais ce que vous stockez sont les bicimales (à gauche). Parfois, ce sont parfaitement les mêmes. Parfois non. Parfois, il semble qu'ils sont les mêmes lorsqu'ils ne le sont tout simplement pas. Voilà l'arrondi.
En particulier, que devons-nous savoir pour pouvoir stocker des valeurs dans une certaine devise et l'imprimer?
S'il vous plaît, si vous manipulez mon argent décimal, n'utilisez pas de flottants ou de doubles.
Si vous êtes sûr que des dixièmes de centimes ne seront pas impliqués, stockez simplement des centimes. Si vous ne l'êtes pas, déterminez quelle sera la plus petite unité de cette monnaie et utilisez-la. Si vous ne le pouvez pas, utilisez quelque chose comme BigDecimal .
Ma valeur nette ira probablement toujours très bien dans un entier 64 bits, mais des choses comme BigInteger fonctionnent bien pour des projets plus grands que cela. Ils sont juste plus lents que les types natifs.
Trouver comment le stocker n'est que la moitié du problème. N'oubliez pas que vous devez également pouvoir l'afficher. Un bon design séparera ces deux choses. Le vrai problème avec l'utilisation de flotteurs ici, c'est que ces deux choses sont mises ensemble.