Ce que j'ai appris du calcul monétaire Java

Préface

J'utilise Java 8 dans mon projet.

Le début de l'affaire

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.

À la recherche du criminel

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.

Pourquoi est-ce éteint?

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.

Capture d'écran 2018-10-16 18.37.13.png par référence

Ce n'est pas bien

double d = 3.3 / 1.1 //Je veux que tu aies 3 mais 2.9999999999999996

Reconfirmez ici comment utiliser Big Decimal (transpiration)

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.

C'est bien que ce ne soit pas bon.

//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).

URL de référence

http://javazuki.com/articles/bigdecimal-usage.html#_roundingmode https://qiita.com/TKR/items/52635175654b9b818b89

2019/11/12 Note personnelle

Le fait que la comparaison de taille (compareTo ()) n'est pas comprise à chaque fois

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

Ce que j'ai appris du calcul monétaire Java
Ce que j'ai appris en étudiant les rails
Ce que j'ai appris avec Java Silver
Ce que j'ai appris
[Note] Ce que j'ai appris en six mois grâce à des inexpérimentés (Java)
[Note] Ce que j'ai appris en six mois grâce à des inexpérimentés (Java) (3)
Ce que j'ai appris en travaillant Java avec Visual Studio Code
Ce que j'ai appris ② ~ Mock ~
Ce que j'ai appris ① ~ DJUnit ~
Ce que j'ai appris en Java (partie 2) Que sont les variables?
Ce que j'ai recherché sur Java 8
Ce que j'ai recherché sur Java 6
Ce que j'ai recherché sur Java 9
Ce que j'ai appris en Java (partie 3) Déclaration d'exécution des instructions
Ce que j'ai appris lors de la création d'un serveur en Java
Ce que j'ai recherché sur Java 7
Ce que j'ai appris sur Kotlin
Ce que j'ai recherché sur Java 5
Ce que j'ai appris en Java (partie 4) Branchement conditionnel et répétition
Ce que j'ai recherché sur l'apprentissage Java
Ce que j'ai appris en Java (partie 1) Flux de développement Java et présentation
Ce à quoi j'ai pensé lorsque j'ai commencé à migrer de Java vers Kotlin
Importance de l'interface apprise de la collection Java
Prenez ce que vous avez appris sur la réflexion Java
[Rails] Ce que j'ai appris d'une petite pierre d'achoppement lors de l'utilisation de l'ascendance
Résumé de ce que j'ai appris sur Spring Boot
Qu'est-ce que 'java
[Java] Que dois-je utiliser pour écrire des fichiers?
J'ai essayé de frapper une méthode Java d'ABCL
Nom de la méthode de la méthode de fabrique statique apprise à partir de Java 8
Qu'est-ce que Java <>?
Qu'est-ce que 'java
Ce que j'ai fait lorsque j'ai converti Java en Kotlin
Je veux écrire rapidement de java vers sqlite
Résumé de ce que j'ai appris dans Spring Batch
[Java] Je souhaite calculer la différence par rapport à la date
J'écrirai quand même ce que j'ai appris sur docker (deuxième)
6 fonctionnalités que j'ai manquées après mon retour de Scala à Java
J'ai essayé d'appeler du code natif Java / Objective-C depuis Flutter
J'écrirai de toute façon ce que j'ai appris sur docker (en premier)
J'ai essayé de découvrir ce qui avait changé dans Java 9
Changements de Java 8 à Java 11
Somme de Java_1 à 100
Java Learning 2 (Apprenez la méthode de calcul)
J'ai d'abord touché Java ③
Évaluer la source Java à partir de Java
J'ai d'abord touché Java ④
Accédez à API.AI depuis Java
De Java à Ruby !!
Qu'est-ce que la technologie Java?
J'ai d'abord touché Java
Qu'est-ce que Java API-java
[Java] Qu'est-ce que flatMap?
[Java] Qu'est-ce que ArrayList?
[JDBC] J'ai essayé d'accéder à la base de données SQLite3 depuis Java.
Je suis entré depuis Rails et je ne savais pas ce qu'était [attr_accessor]