Nous avons récemment mis en place un système qui doit gérer des valeurs dans de multiples devises et convertir entre eux, et a trouvé quelques choses à la dure.
NE JAMAIS UTILISER DES NOMBRES À VIRGULE FLOTTANTE DE L'ARGENT
Arithmétique à virgule flottante introduit des inexactitudes qui peuvent ne pas être remarqué jusqu'à ce qu'ils ont vissé quelque chose. Toutes les valeurs doivent être stockés comme des entiers ou des décimaux types, et si vous choisissez d'utiliser un corrigé-type décimal puis assurez-vous que vous comprenez exactement ce que ce type n'sous le capot (c'est à dire, ne l'interne, l'utilisation d'un nombre entier ou à virgule flottante).
Lorsque vous avez besoin de faire des calculs ou des conversions:
- Convertir des valeurs à virgule flottante
- Calculer la nouvelle valeur
- Arrondir le nombre et la reconvertir en un entier
Lors de la conversion d'un nombre à virgule flottante à un nombre entier dans l'étape 3, ne pas les jeter elle - utiliser une fonction mathématique pour le tour en premier. Ce sera habituellement round
, bien que dans des cas particuliers, il pourrait être floor
ou ceil
. Connaître la différence et choisir avec soin.
Stocker le type d'un nombre à côté de la valeur
Cela peut ne pas être aussi important pour vous si vous êtes seulement de la manipulation de monnaie, mais il était important pour nous dans le traitement des devises multiples. Nous avons utilisé les 3 caractères de code pour une devise, comme l'USD, GBP, JPY, EUR, etc.
Selon la situation, il peut également être utile pour stocker:
- Si le nombre est avant ou après impôt (et que le taux de taxe a)
- Si le nombre est le résultat d'une conversion (et ce qu'il a été converti à partir d')
Connaître la précision des limites des nombres que vous avez à traiter avec des
Pour des valeurs réelles, vous voulez être précis comme la plus petite unité de la devise. Cela signifie que vous n'avez pas de valeurs plus petites que un centime, un centime, un yen, d'un marais, etc. Ne pas stocker des valeurs avec une précision plus élevée que celle pour aucune raison.
En interne, vous pouvez choisir de traiter avec des petites valeurs, auquel cas c'est un autre type de valeur de la monnaie. Assurez-vous que votre code ne sait qui est qui et ne pas les mélanger. Évitez d'utiliser des valeurs à virgule flottante, même ici.
L'ajout de toutes ces règles ensemble, nous avons décidé sur les règles suivantes. Dans le code en cours d'exécution, les monnaies sont stockées à l'aide d'un entier dans la plus petite unité.
class Currency {
String code; // eg "USD"
int value; // eg 2500
boolean converted;
}
class Price {
Currency grossValue;
Currency netValue;
Tax taxRate;
}
Dans la base de données, les valeurs sont stockées en tant que chaîne de caractères dans le format suivant:
USD:2500
Qui stocke la valeur de $25.00. Nous avons été en mesure de le faire seulement parce que le code qui traite des monnaies n'a pas besoin d'être à l'intérieur de la couche de base de données elle-même, de sorte que toutes les valeurs peuvent être converties en mémoire. D'autres situations sera sans aucun doute se prêtent à d'autres solutions.
Et dans le cas où je n'ai pas précisé plus haut, ne pas utiliser de flotter!