105 votes

Java BigDecimal : Arrondir à la valeur entière la plus proche

J'ai essayé de comprendre ce problème, et les questions précédentes sur SO ne m'aident pas non plus

J'ai besoin des résultats suivants

100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

.round() ou .setScale() ? Comment dois-je m'y prendre ? Merci : )

185voto

Grodriguez Points 9945

Vous pouvez utiliser setScale() pour réduire le nombre de chiffres fractionnaires à zéro. En supposant que value contient la valeur à arrondir :

BigDecimal scaled = value.setScale(0, RoundingMode.HALF_UP);
System.out.println(value + " -> " + scaled);

Utilisation de round() est un peu plus complexe car il vous faut préciser le nombre de chiffres à conserver. Dans votre exemple, ce serait 3, mais cela n'est pas valable pour toutes les valeurs :

BigDecimal rounded = value.round(new MathContext(3, RoundingMode.HALF_UP));
System.out.println(value + " -> " + rounded);

(Notez que BigDecimal sont immuables ; les deux setScale et round retournera un nouvel objet).

1 votes

Cela ne fonctionne pas : 100.12 : 100.12, 100.44 : 100.44, 100.50 : 100.5, 100.75 : 100.75

3 votes

Non, le réglage de l'échelle renvoie une nouvelle décimale qui n'est pas la même que la première. Par exemple : BigDecimal bd1 = new BigDecimal(100.12); BigDecimal bd2 = bd1.setScale(0, RoundingMode.HALF_UP); System.out.println(bd1.equals(bd2)); imprime faux

6 votes

@Daniel : C'était déjà implicite dans l'extrait de code que j'ai posté dans ma réponse. Je l'ai maintenant rendu explicite.

16voto

Ramnique Singh Points 638

Si je me fie à la réponse de Grodriguez.

System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

Voici le résultat

100.23 -> 100
100.77 -> 101

Ce qui n'est pas tout à fait ce que je veux, alors j'ai fini par faire ceci

System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
value = value.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

Voici ce que j'obtiens

100.23 -> 100.00
100.77 -> 101.00

Cela résout mon problème pour l'instant : ) Merci à tous.

8 votes

Je suis curieux de l'affirmation selon laquelle le premier résultat "n'est pas tout à fait ce que je veux...". Si vous êtes réellement préoccupé par le formatage de la sortie, vous pouvez utiliser DecimalFormat (dans le mot anglais new DecimalFormat("###.00") ) pour gérer la conversion d'un BigDecimal de retour à la corde. Cela donne "101.00" comme résultat pour les deux valeurs que les snippets de @Grodriquez et vous avez créées.

3 votes

La deuxième fois que vous arrondissez ici est inutile puisque vous savez que vous avez déjà un entier, donc j'utiliserais plutôt BigDecimal.ROUND_UNNECESSARY, un peu plus clair à mon avis.

5voto

Sean Patrick Floyd Points 109428

Voici une solution terriblement compliquée, mais qui fonctionne :

public static BigDecimal roundBigDecimal(final BigDecimal input){
    return input.round(
        new MathContext(
            input.toBigInteger().toString().length(),
            RoundingMode.HALF_UP
        )
    );
}

Code de test :

List<BigDecimal> bigDecimals =
    Arrays.asList(new BigDecimal("100.12"),
        new BigDecimal("100.44"),
        new BigDecimal("100.50"),
        new BigDecimal("100.75"));
for(final BigDecimal bd : bigDecimals){
    System.out.println(roundBigDecimal(bd).toPlainString());
}

Sortie :

100
100
101
101

0 votes

Je ne veux pas cautionner cette solution ou quoi que ce soit, mais la input.toBigInteger().toString().length() serait beaucoup plus efficace en utilisant un logarithme, quelque chose comme round_up(log(input)) + (1 if input is a power of ten, else 0)

0 votes

BigDecimal semble être un tas fumant.

3voto

toolkit Points 27248

Il suffit de regarder :

http://download.oracle.com/javase/6/docs/api/java/math/BigDecimal.html#ROUND_HALF_UP

et :

setScale(int precision, int roundingMode)

Ou si vous utilisez Java 6, alors

http://download.oracle.com/javase/6/docs/api/java/math/RoundingMode.html#HALF_UP

http://download.oracle.com/javase/6/docs/api/java/math/MathContext.html

et soit :

setScale(int precision, RoundingMode mode);
round(MathContext mc);

0voto

Daniel Fath Points 1414

Je ne pense pas que vous puissiez l'arrondir comme ça en une seule commande. Essayez

    ArrayList<BigDecimal> list = new ArrayList<BigDecimal>();
    list.add(new BigDecimal("100.12"));
    list.add(new BigDecimal("100.44"));
    list.add(new BigDecimal("100.50"));
    list.add(new BigDecimal("100.75"));

    for (BigDecimal bd : list){
        System.out.println(bd+" -> "+bd.setScale(0,RoundingMode.HALF_UP).setScale(2));
    }

Output:
100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

J'ai testé pour le reste de vos exemples et il renvoie les valeurs souhaitées, mais je ne garantis pas son exactitude.

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