web-dev-qa-db-fra.com

Pourquoi BigDecimal ("5.50") n'est pas égal à BigDecimal ("5.5") et comment contourner ce problème?

En fait, j'ai trouvé une solution possible

//returns true
new BigDecimal("5.50").doubleValue() == new BigDecimal("5.5").doubleValue()

Bien sûr, il peut être amélioré avec quelque chose comme Math.abs (v1 - v2) < EPS pour rendre la comparaison plus robuste, mais la question est de savoir si cette technique est acceptable ou existe-t-il une meilleure solution?

Si quelqu'un sait pourquoi Java ont décidé d'implémenter les égaux de BigDecimal de cette manière, ce serait intéressant à lire.

48
Roman

Du javadoc de BigDecimal

est égal à

public boolean equals(Object x)

Compare cette BigDecimal avec la Object spécifiée pour l'égalité. Contrairement à compareTo , cette méthode considère deux objets BigDecimal égaux uniquement s'ils sont égaux en valeur et en échelle (donc 2.0 n'est pas égal à 2,00 par rapport à cette méthode) .

Utilisez simplement compareTo() == 0

85
Colin Hebert

Utiliser == Pour comparer les doubles semble être une mauvaise idée en général.

Vous pouvez appeler setScale sur la même chose sur les numéros que vous comparez:

new BigDecimal ("5.50").setScale(2).equals(new BigDecimal("5.5").setScale (2))

où vous définiriez l'échelle sur la plus grande des deux:

BigDecimal a1 = new BigDecimal("5.051");
BigDecimal b1 = new BigDecimal("5.05");
// wow, this is awkward in Java
int maxScale = Collections.max(new ArrayList() {{ a1.scale(), b1.scale()}});
System.out.println(
  a1.setScale(maxScale).equals(b1.setScale(maxScale)) 
  ? "are equal" 
  : "are different" );

Cependant, l'utilisation de compareTo() == 0 est la meilleure réponse. L'augmentation de l'échelle d'un des nombres dans mon approche ci-dessus est probablement "l'inflation inutile" que la documentation de la méthode compareMagnitude mentionne quand elle dit:

/**
 * Version of compareTo that ignores sign.
 */
private int compareMagnitude(BigDecimal val) {
    // Match scales, avoid unnecessary inflation
    long ys = val.intCompact;
    long xs = this.intCompact;

et bien sûr compareTo est beaucoup plus facile à utiliser car il est déjà implémenté pour vous.

9
Nathan Hughes

l'expression la plus simple pour comparer en ignorant les zéros non significatifs est depuis Java 1.5:

bd1.stripTrailingZeros().equals(bd2.stripTrailingZeros())
4
user1708042