Java est Bigdecimal.diviser et arrondi

au travail, nous avons trouvé un problème en essayant de diviser un grand nombre par 1000. Ce nombre est venu à partir de la base de données.

Dire que j'ai de cette méthode:

private static BigDecimal divideBy1000(BigDecimal dividendo) {
    if (dividendo == null) return null;

    return dividendo.divide(BigDecimal.valueOf(1000), RoundingMode.HALF_UP);
}

Quand je fais l'appel suivant

divideBy1000(new BigDecimal("176100000"))

je reçois la valeur attendue de 176100. Mais si j'essaie de la ligne ci-dessous

divideBy1000(new BigDecimal("1761e+5"))

je reçois la valeur 200000. Pourquoi cela se produit? Les deux nombres sont les mêmes avec une représentation différente et la dernière est ce que je reçois de la base de données. Je comprendre que, d'une certaine manière, la JVM divise le nombre 1761 par 1000, arrondir et remplir avec 0 à la fin.

Quelle est la meilleure façon d'éviter ce genre de comportement? Gardez à l'esprit que le nombre initial n'est pas contrôlée par moi.

21
demandé sur Raphael do Vale 2014-10-19 20:47:39

5 réponses

comme spécifié dans javadoc, a BigDecimal est défini par une valeur entière et un échelle.

la valeur du nombre représenté par le BigDecimal est donc (valeur non évaluée × 10^(- échelle)).

BigDecimal("1761e+5") a l'échelle de -5 et BigDecimal(176100000) a l'échelle 0.

La division des deux BigDecimal est fait en utilisant les échelles -5 et 0 respectivement parce que les échelles ne sont pas spécifiées lors de la division. divide documentation explique pourquoi les résultats sont différents.

divide

public BigDecimal divide(BigDecimal divisor)

renvoie un BigDecimal dont la valeur est (this / divisor), et dont l'échelle préféré est (this.scale() - divisor.scale()); si le quotient exact ne peut pas être représenté (parce qu'il a une expansion décimale sans fin) un ArithmeticException est levée.

Paramètres:

divisor - valeur par laquelle ce Granddécimal est pour être divisé.

Renvoie:

this / divisor

lancers:

ArithmeticException - si le quotient exact n'a pas d'expansion décimale finale

Car:

1,5

si vous spécifiez une échelle lors de la division, par exemple dividendo.divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP) vous aurez le même résultat.

19
répondu dcernahoschi 2014-10-19 18:23:16

les expressions new BigDecimal("176100000") et new BigDecimal("1761e+5")différent. BigDecimal garde une trace de la valeur et de la précision.

BigDecimal("176100000") a 9 chiffres de précision et est représenté à l'intérieur comme le BigInteger("176100000"), multiplié par 1. BigDecimal("1761e+5") a 4 chiffres de précision et est représenté à l'intérieur comme le