Java BigDecimal: Zaokrąglij do najbliższej wartości całkowitej

90

Potrzebuję następujących wyników

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

.round()czy .setScale()? Jak mam się do tego zabrać?

na
źródło

Odpowiedzi:

153

Możesz użyć, setScale()aby zmniejszyć liczbę cyfr ułamkowych do zera. Zakładając, że valuema wartość do zaokrąglenia:

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

Używanie round()jest nieco bardziej skomplikowane, ponieważ wymaga określenia liczby przechowywanych cyfr. W twoich przykładach będzie to 3, ale nie jest to poprawne dla wszystkich wartości:

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

(Zauważ, że BigDecimalobiekty są niezmienne; oba setScalei roundzwrócą nowy obiekt).

Grodriguez
źródło
1
To nie działa: 100,12: 100,12, 100,44: 100,44, 100,50: 100,5, 100,75: 100,75
Boris Pavlović
3
Nie, ustawienie skali zwraca nową liczbę dziesiętną, która nie jest taka sama jak pierwsza. Na przykład: BigDecimal bd1 = new BigDecimal(100.12); BigDecimal bd2 = bd1.setScale(0, RoundingMode.HALF_UP); System.out.println(bd1.equals(bd2));drukuje fałsz
Daniel Fath
6
@Daniel: To było już zasugerowane we fragmencie kodu, który zamieściłem w mojej odpowiedzi. Teraz wyraziłem to wyraźnie.
Grodriguez
RoundingModeco to jest? JestBigDecimal
trylogia
10

Jeśli pójdę na odpowiedź Grodrigueza

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

To jest wynik

100.23 -> 100
100.77 -> 101

Co nie jest tym, czego chcę, więc w końcu to zrobiłem ...

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

Oto, co dostaję

100.23 -> 100.00
100.77 -> 101.00

To na razie rozwiązuje mój problem .. :) Dziękuję wszystkim.

na
źródło
7
Ciekawi mnie stwierdzenie, że pierwszy wynik „nie jest tym, czego chcę…”. Jeśli naprawdę martwisz się formatowaniem wyjściowym, możesz użyć DecimalFormat(as in new DecimalFormat("###.00")) do zarządzania konwersją z BigDecimalpowrotem do łańcucha. Daje "101.00"wynik dla obu wartości utworzonych przez fragmenty z @Grodriquez i przez Ciebie.
joel.neely
3
Drugie zaokrąglanie w tym miejscu jest niepotrzebne, ponieważ wiesz, że masz już liczbę całkowitą, więc zamiast tego użyłbym BigDecimal.ROUND_UNNECESSARY, moim zdaniem nieco bardziej przejrzysty.
kosmoplan
5

Oto strasznie skomplikowane rozwiązanie, ale działa:

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

Kod testu:

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());
}

Wynik:

100
100
101
101,

Sean Patrick Floyd
źródło
Nie popierać tego rozwiązania ani niczego, ale input.toBigInteger().toString().length()część byłaby znacznie bardziej wydajna przy użyciu logarytmu, coś takiego jakround_up(log(input)) + (1 if input is a power of ten, else 0)
Addison
0

Nie sądzę, aby można było to tak zaokrąglić jednym poleceniem. Próbować

    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

Przetestowałem resztę twoich przykładów i zwraca żądane wartości, ale nie gwarantuję jego poprawności.

Daniel Fath
źródło
-2

Chcesz

round(new MathContext(0));  // or perhaps another math context with rounding mode HALF_UP
jacobm
źródło
2
To nic nie daje. Z dokumentacji round: „Jeśli ustawienie dokładności wynosi 0, zaokrąglanie nie następuje”.
Grodriguez