BigDecimal se multiplie par zéro

Je réalise une multiplication simple avec BigDecimal et j’ai trouvé un comportement étrange en multipliant par zéro (multiplier par zéro est correct dans ce cas d’utilisation).

Les maths de base me disent que tout ce qui est multiplié par zéro sera égal à zéro (voir: Propriétés du produit nul et propriétés de multiplication )

Toutefois, le code suivant échouera systématiquement avec la même erreur:

assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0))); 
 java.lang.AssertionError: Expected :0 Actual :0E-48 

Est-ce une inexactitude avec BigDecimal ou y a-t-il une twig de maths de niche qui me manque quelque part?

Notes: JDK 1.6.0_27 en cours d’exécution dans IntelliJ 11

Vous ne pouvez pas utiliser la méthode equals() pour comparer BigDecimals , comme le fait cette assertion. C’est parce que cette fonction est égale à comparer l’échelle . Si l’échelle est différente, equals() renverra false, même si elles sont mathématiquement identiques.

Vous pouvez cependant utiliser compareTo() pour faire ce que vous voulez:

Comme @assylias le souligne, vous devez également utiliser le new BigDecimal("22.3") pour éviter les problèmes de double précision.

 BigDecimal expected = BigDecimal.ZERO; BigDecimal actual = new BigDecimal("22.3").multiply(BigDecimal.ZERO); assertEquals(0, expected.compareTo(actual)); 

Il y a aussi une méthode appelée signum() , qui renvoie -1, 0 ou 1 pour négatif, zéro et positif. Donc, vous pouvez également tester zéro avec

 assertEquals(0, actual.signum()); 

Il y a 2 problèmes avec votre code:

  • vous devriez comparer BigDecimal avec compareTo au lieu de égal, comme conseillé par les autres réponses
  • mais vous devez également utiliser le constructeur de chaîne: new BigDecimal("22.3") au lieu du constructeur double new BigDecimal(22.3) pour éviter les problèmes de double précision

En d’autres termes, le code suivant (qui utilise correctement compareTo) renvoie toujours false:

 BigDecimal bd = new BigDecimal(0.1).multiply(new BigDecimal(10)); System.out.println(bd.compareTo(BigDecimal.ONE) == 0); 

parce que 0.1d * 10d != 1

equals() sur BigDecimal vérifie l’état interne de BigDecimal pour comparaison

Reportez le code ci-dessous

 public boolean equals(Object x) { if (!(x instanceof BigDecimal)) return false; BigDecimal xDec = (BigDecimal) x; if (x == this) return true; if (scale != xDec.scale) return false; long s = this.intCompact; long xs = xDec.intCompact; if (s != INFLATED) { if (xs == INFLATED) xs = compactValFor(xDec.intVal); return xs == s; } else if (xs != INFLATED) return xs == compactValFor(this.intVal); return this.inflate().equals(xDec.inflate()); } 

si vous voulez comparer les valeurs, utilisez compareTo()

Changez votre code pour

 assertEquals(0 , new BigDecimal(0).compareTo(new BigDecimal(22.3).multiply(new BigDecimal(0))); 

Mettre à jour:

Utilisez le constructeur en prenant Ssortingng comme paramètre pour BigDecimal pour une précision de précision. Consultez les liens connexes ci-dessous.


Regarde aussi

  • Obtenir un résultat erroné pour l’évaluation de 100 * 2,55 valeurs
  • Les bogues Java BigDecimal avec le constructeur Ssortingng à arrondir avec ROUND_HALF_UP