Dois-je utiliser NSDecimalNumber pour traiter de l’argent?

Comme j’ai commencé à coder ma première application, j’ai utilisé NSNumber pour des valeurs sans réfléchir à deux fois. Ensuite, j’ai pensé que les types c étaient peut-être suffisants pour gérer mes valeurs. Pourtant, le forum SDK de l’iPhone m’a conseillé d’utiliser NSDecimalNumber en raison de ses excellentes capacités d’arrondi.

N’étant pas un mathématicien par tempérament, j’ai pensé que le paradigme de la mantisse / exposant pouvait être exagéré; Pourtant, googlin ‘around, je me suis rendu compte que la plupart des discussions sur l’argent / la monnaie dans le cacao avaient été renvoyées à NSDecimalNumber.

Notez que l’application sur laquelle je travaille va être internationalisée, donc l’option de compter le montant en cents n’est pas vraiment viable, car la structure monétaire dépend beaucoup de la localisation utilisée.

Je suis sûr à 90% que je dois utiliser NSDecimalNumber, mais comme je n’ai pas trouvé de réponse sans ambiguïté sur le Web (quelque chose comme: “si vous traitez avec de l’argent, utilisez NSDecimalNumber!”) Peut-être que la réponse est évidente pour la plupart, mais je veux être sûr avant de commencer une re-factorisation massive de mon application.

Me convaincre 🙂

    Marcus Zarra a une position assez claire à ce sujet: “Si vous avez affaire à de la monnaie, vous devriez utiliser NSDecimalNumber.” Son article m’a inspiré à regarder NSDecimalNumber et cela m’a beaucoup impressionné. Les erreurs à virgule flottante IEEE lorsqu’il s’agit de calculs basés sur la base 10 m’ont longtemps irritée (1 * (0.5 – 0.4 – 0.1) = -0.00000000000000002776) et NSDecimalNumber les supprime.

    NSDecimalNumber ne se contente pas d’append quelques chiffres de précision binary en virgule flottante, il effectue en fait des calculs de base 10. Cela élimine les erreurs comme celle illustrée dans l’exemple ci-dessus.

    Maintenant, j’écris une application mathématique symbolique, donc mon désir d’obtenir une précision de plus de 30 chiffres et aucune erreur en virgule flottante pourrait être une exception, mais je pense que cela vaut la peine de le regarder. Les opérations sont un peu plus compliquées que les simples maths de style var = 1 + 2, mais elles sont toujours gérables. Si vous craignez d’allouer toutes sortes d’instances lors de vos opérations mathématiques, NSDecimal est l’équivalent C struct de NSDecimalNumber et il existe des fonctions C pour effectuer exactement les mêmes opérations mathématiques. D’après mon expérience, ces applications sont très rapides, sauf pour les applications les plus exigeantes (3 344 593 additions / s, 254 017 divisions / s sur un MacBook Air, 281 555 additions / s, 12 027 divisions / s sur un iPhone).

    Comme bonus supplémentaire, la méthode descriptionWithLocale: de NSDecimalNumber fournit une chaîne avec une version localisée du numéro, y compris le séparateur décimal correct. La même chose est inversée pour sa méthode initWithSsortingng: locale:.

    Oui. Vous devez utiliser

    NSDecimalNumber et

    ne pas doubler ni flotter lorsque vous traitez avec une devise sur iOS.

    Pourquoi donc??

    Parce que nous ne voulons pas obtenir des choses comme 9,9999999998 $ au lieu de 10 $

    Comment ça se passe ??

    Les flotteurs et les doubles sont des approximations. Ils viennent toujours avec une erreur d’arrondi. Le format utilisé par les ordinateurs pour stocker les nombres décimaux provoque cette erreur de routage. Si vous avez besoin de plus de détails, lisez

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

    Selon Apple Documents,

    NSDecimalNumber est une sous-classe immuable de NSNumber, fournit un wrapper orienté object pour effectuer des calculs arithmétiques de base 10. Une instance peut représenter n’importe quel nombre pouvant être exprimé en mantisse x 10 ^ exposant où la mantisse est un entier décimal comportant jusqu’à 38 chiffres, et exposant un nombre entier compris entre –128 et 127.wrapper pour effectuer des calculs arithmétiques de base 10.

    Donc NSDecimalNumber est recommandé pour traiter avec la devise.

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

    Oui tu devrais. Un nombre entier de centimes ne fonctionne que tant que vous n’avez pas besoin de représenter un demi-cent, par exemple. Si cela se produit, vous pouvez le changer pour compter les demi-centimes, mais que faire si vous devez alors représenter un quart de cent, ou un huitième de centime?

    La seule solution appropriée est NSDecimalNumber (ou quelque chose comme ça), qui remet le problème à 10 ^ -128 ¢ (c.-à-d.
    0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    000000000000000000000000000000000000001 ¢).

    (Une autre façon serait l’arithmétique de précision arbitraire, mais cela nécessite une bibliothèque séparée, telle que la bibliothèque GNU MP Bignum . GMP est sous la LGPL. Je n’ai jamais utilisé cette bibliothèque et je ne sais pas exactement comment cela fonctionne, donc je ne pouvait pas dire à quel point cela fonctionnerait pour vous.)

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

    Une meilleure question est de savoir quand ne pas utiliser NSDecimalNumber pour gérer 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 ne vous souciez pas des petites erreurs d’arrondi, car vous ne traitez jamais que 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.

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

    VISA, MasterCards et autres utilisent des valeurs entières lors du passage de montants. Il appartient à l’expéditeur et au destinataire d’parsingr correctement les entrées en fonction de l’exposant monétaire (diviser ou multiplier par 10 ^ num, où num – est un exposant de la devise). Notez que les différentes devises ont des exposants différents. En général, c’est 2 (nous divisons et multiplions par 100), mais certaines devises ont un exposant = 0 (VND, etc.), ou = 3.