68 votes

Meilleur moyen de stocker des valeurs monétaires en C++

Je sais qu'un flottant n'est pas approprié pour stocker des valeurs monétaires en raison des erreurs d'arrondi. Existe-t-il un moyen standard de représenter la monnaie en C++ ?

J'ai regardé dans la bibliothèque de boost et je n'ai rien trouvé à ce sujet. En Java, il semble que BigInteger soit la solution, mais je n'ai pas trouvé d'équivalent en C++. Je pourrais écrire ma propre classe d'argent, mais je préfère ne pas le faire s'il y a quelque chose de testé.

34voto

Eclipse Points 27662

Ne les stockez pas sous forme de centimes, car vous accumulerez rapidement des erreurs lors de la multiplication pour les impôts et les intérêts. Conservez au moins deux chiffres significatifs supplémentaires : 12,45 $ seront stockés sous la forme de 124 500. Si vous le conservez sous la forme d'un nombre entier signé de 32 bits, vous pourrez travailler avec 200 000 dollars (positifs ou négatifs). Si vous avez besoin de nombres plus grands ou d'une plus grande précision, un entier signé de 64 bits vous donnera probablement tout l'espace dont vous aurez besoin pendant longtemps.

Il pourrait être utile d'envelopper cette valeur dans une classe, afin de disposer d'un endroit unique pour créer ces valeurs, effectuer des calculs sur elles et les formater pour l'affichage. Cela vous donnerait également un endroit central pour transporter la devise dans laquelle elle est stockée (USD, CAD, EURO, etc.).

29voto

Orion Adrian Points 8855

Ayant eu affaire à ce problème dans des systèmes financiers réels, je peux vous dire que vous souhaitez probablement utiliser un nombre avec une précision d'au moins 6 décimales (en supposant qu'il s'agisse de dollars américains). Comme vous parlez de valeurs monétaires, j'espère que vous ne vous tromperez pas. Il existe des propositions pour ajouter des types décimaux au C++, mais je n'en connais aucune qui soit encore en vigueur.

Le meilleur type natif C++ à utiliser ici serait long double.

Le problème avec les autres approches qui utilisent simplement un int est que vous devez stocker plus que vos cents. Souvent, les transactions financières sont multipliées par des valeurs non entières et cela va vous poser des problèmes puisque 100,25 $ traduits en 10025 * 0,000123523 (par exemple le TAEG) vont poser des problèmes. Vous allez finir par vous retrouver au pays des virgules flottantes et les conversions vont vous coûter cher.

Le problème ne se pose pas dans la plupart des situations simples. Je vais vous donner un exemple précis :

Si vous multipliez plusieurs milliers de valeurs monétaires par un pourcentage et que vous les additionnez, vous obtiendrez un chiffre différent de celui que vous auriez obtenu en multipliant le total par ce pourcentage si vous ne conservez pas suffisamment de décimales. Cela peut fonctionner dans certaines situations, mais il vous manquera souvent plusieurs centimes assez rapidement. D'après mon expérience générale, il faut veiller à conserver une précision allant jusqu'à 6 décimales (en s'assurant que la précision restante est disponible pour la partie du nombre entier).

Comprenez également que le type de stockage n'a pas d'importance si vous faites des calculs de manière moins précise. Si vos calculs sont effectués en simple précision, il importe peu que vous les stockiez en double précision. Votre précision sera correcte jusqu'au calcul le moins précis.


Cela dit, si vous ne faites pas d'autres calculs que de simples additions ou soustractions et que vous stockez ensuite le nombre, tout ira bien, mais dès qu'il y aura quelque chose de plus complexe, vous aurez des problèmes.

24voto

jblocksom Points 4504

Regardez dans le relativement récent Bibliothèque mathématique à virgule flottante Intelr Decimal . Il est spécialement conçu pour les applications financières et met en œuvre certaines des fonctionnalités de l'application. nouvelles normes pour l'arithmétique binaire à virgule flottante (IEEE 754r) .

13voto

user331471 Points 352

Le plus gros problème est l'arrondi lui-même !

19% de 42,50 € = 8,075 €. En raison des règles allemandes d'arrondi, ce chiffre est de 8,08 €. Le problème est que (du moins sur ma machine) 8,075 ne peut pas être représenté comme un double. Même si je change la variable dans le débogueur pour cette valeur, je me retrouve avec 8,0749999.....

Et c'est là que ma fonction d'arrondi (et toute autre logique à virgule flottante à laquelle je peux penser) échoue, puisqu'elle produit 8,07 €. Le chiffre significatif est 4 et donc la valeur est arrondie vers le bas. C'est tout simplement faux et vous ne pouvez rien y faire à moins d'éviter d'utiliser des valeurs à virgule flottante dans la mesure du possible.

Cela fonctionne très bien si vous représentez 42,50 € en tant que nombre entier 42500000.

42500000 * 19 / 100 = 8075000. Vous pouvez maintenant appliquer la règle d'arrondi au-dessus de 8080000. Cette valeur peut facilement être transformée en une valeur monétaire pour des raisons d'affichage. 8,08 €.

Mais je terminais toujours ça dans un cours.

9voto

Rontologist Points 2350

Je vous suggère de conserver une variable pour le nombre de centimes au lieu de dollars. Cela devrait supprimer les erreurs d'arrondi. L'affichage dans le format standard dollars/cents devrait être un problème d'affichage.

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