81 votes

Comment résoudre un problème Java Rounding Double

On dirait que la soustraction déclenche une sorte de problème et que la valeur résultante est fausse.

 double tempCommission = targetPremium.doubleValue()*rate.doubleValue()/100d;
 

78,75 = 787,5 * 10,0 / 100d

 double netToCompany = targetPremium.doubleValue() - tempCommission;
 

708,75 = 787,5 - 78,75

 double dCommission = request.getPremium().doubleValue() - netToCompany;
 

877.8499999999999 = 1586,6 - 708,75

La valeur attendue qui en résulterait serait 877,85.

Que faut-il faire pour assurer le bon calcul?

101voto

Eric Weilnau Points 1968

Pour contrôler la précision de l'arithmétique à virgule flottante, vous devez utiliser java.les mathématiques.BigDecimal. Lire La nécessité pour BigDecimal par John Zukowski pour plus d'informations.

Compte tenu de votre exemple, la dernière ligne serait comme suit à l'aide de BigDecimal.

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf(1586.6d);
BigDecimal netToCompany = BigDecimal.valueOf(708.75d);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

Cette résultats dans la sortie suivante.

877.85 = 1586.6 - 708.75

75voto

Johann Zacharee Points 695

Comme les réponses précédentes, ce est une conséquence de faire arithmétique à virgule flottante.

Comme une affiche précédente a suggéré, Quand vous faites des calculs numériques, l'utilisation de java.les mathématiques.BigDecimal.

Cependant, il y a une chasse aux sorcières à l'aide de BigDecimal. Lors de la conversion de la valeur de type double pour un BigDecimal, vous avez le choix de l'utilisation d'un new BigDecimal(double), le constructeur ou le BigDecimal.valueOf(double) statique méthode de fabrique. L'utilisation de la statique méthode de fabrique.

Le double constructeur convertit l'ensemble de la précision de la double à un BigDecimal alors que la statique de l'usine efficacement la convertit en une chaîne de caractères, puis la convertit en un BigDecimal.

C'est important lorsque vous êtes en cours d'exécution dans ces subtiles erreurs d'arrondi. Un certain nombre peuvent afficher .585, mais en interne, c'est la valeur est 0.58499999999999996447286321199499070644378662109375'. Si vous avez utilisé le BigDecimal constructeur, vous obtenez le nombre n'est PAS égal à 0.585, tandis que la méthode statique serait de vous donner une valeur égale à 0.585.


double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));

sur mon système donne

0.58499999999999996447286321199499070644378662109375
0.585

10voto

toolkit Points 27248

Un autre exemple:

 double d = 0;
for (int i = 1; i <= 10; i++) {
    d += 0.1;
}
System.out.println(d);    // prints 0.9999999999999999 not 1.0
 

Utilisez BigDecimal à la place.

MODIFIER:

De plus, je tiens à souligner que ce n’est pas un problème d’arrondi «Java». D'autres langues présentent un comportement similaire (mais pas nécessairement cohérent). Java garantit au moins un comportement cohérent à cet égard.

7voto

Steve Klabnik Points 1621

Chaque fois que vous effectuez des calculs avec des doubles, cela peut arriver. Ce code vous donnerait 877.85:

double réponse = Math.round (dCommission * 100000) / 100000.0;

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