53 votes

Devrais-je utiliser NSDecimalNumber pour gérer de l'argent?

Comme j'ai commencé à coder ma première application que j'ai utilisé NSNumber pour les valeurs de la monnaie sans réfléchir à deux fois. Puis j'ai pensé que peut-être c types ont été assez à faire avec mes valeurs. Pourtant, j'ai été conseillé dans le SDK de l'iPhone forum à utiliser NSDecimalNumber, en raison de son excellente arrondissement capacités.

N'étant pas mathématicien, par tempérament, je pensais que la mantisse/exposant paradigme peut-être exagéré; encore, googlin' autour, j'ai réalisé que la plupart parle d'argent/monnaie de cacao ont été mentionnés NSDecimalNumber.

Notez que l'application que je suis en train de travailler sur va être internationalisées, de sorte que la possibilité de compter le montant en centimes, c'est pas vraiment viable, de la politique monétaire de la structure dépend de la locale utilisée.

Je suis sûr à 90% que j'ai besoin d'aller avec NSDecimalNumber, mais depuis je n'ai pas trouvé de réponse précise sur le web (quelque chose comme: "si vous faites affaire avec de l'argent, de l'utilisation NSDecimalNumber!") Je pensais que je voudrais poser ici. Peut-être que la réponse est évidente pour la plupart, mais je veux être sûr avant de commencer un massif de re-factoring de mon application.

Me convaincre :)

64voto

Brad Larson Points 122629

Marcus Zarra a une jolie position claire sur ce point: "Si vous traitez avec de la monnaie à tous, alors vous devriez être en utilisant NSDecimalNumber." Son article m'a incité à regarder dans NSDecimalNumber, et j'ai été très impressionné. En virgule flottante IEEE erreurs lorsque vous traitez avec base-10 mathématiques ont été irritant de moi pendant un moment (1 * (0.5 - 0.4 - 0.1) = -0.00000000000000002776) et NSDecimalNumber n'loin avec eux.

NSDecimalNumber n'est pas juste ajouter un autre quelques chiffres de binaire à virgule flottante de précision, il ne fait en base 10 de mathématiques. Cela se débarrasser des erreurs comme montré dans l'exemple ci-dessus.

Maintenant, je suis de l'écriture symbolique mathématique de l'application, de sorte que mon désir de 30+ les chiffres de précision et plus d'étranges virgule flottante erreurs peut-être une exception, mais je pense qu'il vaut la peine de regarder. Les opérations sont un peu plus difficile que de simples var = 1 + 2 style de mathématiques, mais ils sont encore gérables. Si vous êtes inquiet au sujet de l'allocation de toutes sortes de cas au cours de vos opérations mathématiques, NSDecimal est la structure C équivalent de NSDecimalNumber et il existe des fonctions C pour faire exactement les mêmes opérations mathématiques avec elle. Dans mon expérience, ce sont beaucoup rapide pour tous, mais les applications les plus exigeantes (3,344,593 ajouts/s, 254,017 divisions/s sur un MacBook Air, 281,555 ajouts/s, 12,027 divisions/s sur un iPhone).

Comme un bonus supplémentaire, NSDecimalNumber de descriptionWithLocale: méthode fournit une chaîne de caractères avec une version localisée de le numéro, y compris le bon séparateur décimal. Il en va de même en sens inverse pour son initWithString:paramètres: la méthode.

10voto

MadNik Points 1131

Oui. Vous devez utiliser

NSDecimalNumber et

pas de double ou float lorsque vous traitez avec de la monnaie sur iOS.

Pourquoi est-ce??

Parce que nous ne voulons pas faire les choses comme $9.9999999998 au lieu de $10

Comment ça se passe??

Les chars et les doubles sont des approximations. Ils ont toujours livré avec une erreur d'arrondi. Le format ordinateurs utilisent pour stocker les décimales cause de cette rouding erreur. Si vous avez besoin de plus de détails, lisez

http://floating-point-gui.de/

Selon apple docs,

NSDecimalNumber est immuable sous-classe de NSNumber, fournit une orientée objet wrapper pour faire en base 10 de l'arithmétique. Un exemple peut représenter n'importe quel nombre qui peut être exprimé comme la mantisse x 10^exposant où la mantisse est un nombre entier décimal jusqu'à 38 chiffres de long, et l'exposant est un entier allant de -128 à 127.wrapper pour faire en base 10 de l'arithmétique.

Donc NSDecimalNumber est recommonded pour faire face à la monnaie.

5voto

Peter Hosey Points 66275

(Adapté de mon commentaire sur l'autre réponse.)

Oui, vous devriez le faire. Intégrante nombre de pièces d'un cent ne fonctionne que tant que vous n'avez pas besoin de représenter, disons, un demi-cent. Si cela se produit, vous pouvez le changer à compter de la demi-cents, mais que faire si vous devez représenter un quart de cent, ou un huitième de un cent?

La seule bonne solution est NSDecimalNumber (ou quelque chose comme ça), qui met du problème à 10^-128¢ (c'est à dire,
0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000001¢).

(Une autre façon serait arbitraire calcul en précision, mais qui nécessite une bibliothèque distincte, comme la GNU MP Bignum de la bibliothèque. GMP est sous LGPL. Je n'ai jamais utilisé cette bibliothèque et ne sais pas exactement comment il fonctionne, donc je ne pourrais pas dire comment il pourrait travailler pour vous.)

[Edit: Apparemment, au moins une personne-Brad Larson pense que je parle de binaire à virgule flottante quelque part dans cette réponse. Je ne suis pas.]

4voto

Tony Points 2331

Une meilleure question est de savoir quand ne pas utiliser NSDecimalNumber pour gérer de l'argent. La réponse courte à cette question est la suivante: lorsque vous ne pouvez pas tolérer la surcharge de performances de NSDecimalNumber et que vous vous moquez des petites erreurs d’arrondi car vous n’avez jamais affaire à plus de quelques chiffres de précision. La réponse encore plus courte est que vous devez toujours utiliser NSDecimalNumber lorsque vous traitez avec de l'argent.

3voto

wisequark Points 2748

J'ai trouvé pratique d'utiliser un entier pour représenter le nombre de centimes, puis de le diviser par 100 pour la présentation. Évite toute la question.

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