J'utilise Java 8 dans mon projet.
Je code en Java qui implique un calcul monétaire et la valeur affichée à l'écran est
299.999999999999988897769753748434595763683319091796875000
J'ai rencontré un événement qui a légèrement dévié comme ça. J'ai honte de dire que j'ai écrit la logique pour calculer correctement le montant (?) Pour la première fois, alors J'ai procédé en enquêtant sur la raison pour laquelle cela s'est produit.
Dans la première étape du traitement, telle que la multiplication du montant par un pourcentage
//Pourcentage et montant obtenu à partir d'un modèle
double d = 0.3;
BigDecimal bd = new BigDecimal("1000");
//Calcul
BigDecimal bd2 = bd.multiply(new BigDecimal(d));
System.out.println(bd2); // 299.999999999999988897769753748434595763683319091796875000
Vous créiez une instance BigDecimal en passant le double argument au constructeur. Suite à son extraction depuis la base de données, le champ de modèle utilisé dans la classe Servive a été défini comme un type double.
Bien qu'il soit défini en décimal dans le code, il est géré en binaire en interne, donc Les valeurs qui sont des fractions binaires et circulaires (par exemple, le double de 0,3) seront arrondies, c'est-à-dire qu'une erreur se produira.
par référence
double d = 3.3 / 1.1 //Je veux que tu aies 3 mais 2.9999999999999996
J'ai lu la référence pour le moment. https://docs.oracle.com/javase/jp/8/docs/api/java/math/BigDecimal.html
- add - subtract - multiply - divide Exécutez quatre règles en utilisant des méthodes telles que. Spécifiez arrondi / arrondi / arrondi en mode arrondi. Cette fois, la logique n'était pas si compliquée, donc je n'ai pas utilisé de méthodes compliquées.
//Génération d'instance à chaque fois, inefficace
BigDecimal b1 = new BigDecimal(10); //Pas bien
//Utiliser le cache valueOf()
BigDecimal b2 = BigDecimal.valueOf(10); //bien
//∵ Une erreur se produira si le nombre binaire est une fraction circulaire.
BigDecimal b3 = new BigDecimal(0.3); //Pas bien
//Générer à partir d'une chaîne
BigDecimal b4 = new BigDecimal("0.3"); //bien
//Lorsque vous souhaitez convertir la valeur de double en BigDecimal
BigDecimal b5 = BigDecimal.valueOf(0.3); //(Je ne souhaite pas implémenter cette conversion si possible)
La série --BigDecimal # ROUND_xxxx est obsolète dans Java 9 ou version ultérieure. Utilisons RoundingMode (Java8 est utilisé dans le projet actuel, mais je serai conscient de cela en prévision de la mise à niveau de la version).
http://javazuki.com/articles/bigdecimal-usage.html#_roundingmode https://qiita.com/TKR/items/52635175654b9b818b89
BigDecimal three = BigDecimal.valueOf(3);
BigDecimal five = BigDecimal.valueOf(5);
int hoge = three.compareTo(five); // -1
int piyo = three.compareTo(three); // 0
int fuga = five.compareTo(three); // 1
Recommended Posts