BigDecimal, division et MathContext - un comportement très étrange
-
22-09-2019 - |
Question
CentOS 5.4, OpenJDK Runtime Environment (build 1.6.0-b09)
MathContext context = new MathContext(2, RoundingMode.FLOOR);
BigDecimal total = new BigDecimal("200.0", context);
BigDecimal goodPrice = total.divide(BigDecimal.valueOf(3), 2, RoundingMode.FLOOR);
System.out.println("divided price=" + goodPrice.toPlainString());
// prints 66.66
BigDecimal goodPrice2 = total.divide(BigDecimal.valueOf(3), new MathContext(2, RoundingMode.FLOOR));
System.out.println("divided price2=" + goodPrice2.toPlainString());
// prints 66
BUG?
La solution
Javadoc pour la première situation:
Retourne une BigDecimal dont la valeur est (ce / diviseur), et dont la dimension est telle que spécifiée. Si l'arrondi doit être effectuée pour générer un résultat à l'échelle spécifiée, le mode d'arrondi spécifié est appliqué.
et le Javadoc pour la deuxième situation:
Retourne une BigDecimal dont la valeur est (ce / diviseur), avec arrondi en fonction des paramètres du contexte.
se référant à la javadoc pour MathContext nous obtenons:
objets immuables qui encapsulent les paramètres de contexte qui décrivent certaines règles pour les opérateurs numériques, tels que ceux mis en œuvre par le classe BigDecimal. La base indépendante les paramètres sont les suivants: précision: le nombre de chiffres à utiliser pour une opération; les résultats sont arrondis à cette précision roundingMode: un objet RoundingMode qui spécifie l'algorithme à utilisé pour arrondir.
Ainsi, dans le premier cas, vous avez spécifié une échelle de 2, ce qui signifie que vous arrondir à 2 décimales de précision, où l'arrondissement est effectué en fonction du sol. Le second calcul a une précision spécifiée de 2 qui est arrondie à deux chiffres de précision, où l'arrondi est une fonction de plancher. Ainsi, dans le premier cas, vous avez demandé 2 chiffres après la virgule , et dans le second, vous venez de poser 2 chiffres. Si, par exemple, vous aviez demandé 4 chiffres dans votre MathContext, vous obtiendrez 66,66 que vous répondez.
Je ne pense pas que ce soit un bug tant que que les deux méthodes ne fonctionnent pas le même calcul.
Autres conseils
Ceci est tout à fait le comportement attendu. Je pense que vous faites l'erreur et l'arrondissement (à l'échelle) mélanger et précision.
total.divide(BigDecimal.valueOf(3), 2, RoundingMode.FLOOR)
ici vous remplacez votre MathContext et l'utilisation d'un arrondi.
total.divide(BigDecimal.valueOf(3), new MathContext(2, RoundingMode.FLOOR))
ici vous définissez une précision de 2 et recevoir seulement 2 chiffres.
Lecture de la Javadoc pour la fracture méthode (BigDecimal, MathContext), il semble que seul le mode d'arrondi du contexte est pris en compte.