Java BigDecimal: Membulatkan ke seluruh nilai terdekat

90

Saya membutuhkan hasil sebagai berikut

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

.round()atau .setScale()? Bagaimana saya melakukan ini?

na
sumber

Jawaban:

153

Anda dapat menggunakan setScale()untuk mengurangi jumlah digit pecahan menjadi nol. Dengan asumsi valuememegang nilai yang akan dibulatkan:

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

Penggunaan round()sedikit lebih rumit karena mengharuskan Anda menentukan jumlah digit yang akan dipertahankan. Dalam contoh Anda ini akan menjadi 3, tetapi ini tidak valid untuk semua nilai:

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

(Perhatikan bahwa BigDecimalobjek tidak dapat diubah; keduanya setScaledan roundakan mengembalikan objek baru.)

Grodriguez
sumber
1
Tidak berfungsi: 100.12: 100.12, 100.44: 100.44, 100.50: 100.5, 100.75: 100.75
Boris Pavlović
3
Tidak, skala pengaturan mengembalikan desimal baru yang tidak sama dengan yang pertama. Misalnya: BigDecimal bd1 = new BigDecimal(100.12); BigDecimal bd2 = bd1.setScale(0, RoundingMode.HALF_UP); System.out.println(bd1.equals(bd2));cetakan salah
Daniel Fath
6
@Daniel: Itu sudah tersirat dalam potongan kode yang saya posting di jawaban saya. Saya sekarang telah membuatnya eksplisit.
Grodriguez
RoundingModeapa itu? IniBigDecimal
trilogi
10

Jika saya mengikuti jawaban Grodriguez

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

Ini adalah hasilnya

100.23 -> 100
100.77 -> 101

Yang tidak sesuai dengan keinginan saya, jadi saya akhirnya melakukan ini ..

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

Inilah yang saya dapatkan

100.23 -> 100.00
100.77 -> 101.00

Ini memecahkan masalah saya untuk saat ini .. :) Terima kasih semua.

na
sumber
7
Saya ingin tahu tentang pernyataan bahwa hasil pertama "tidak seperti yang saya inginkan ...". Jika Anda benar-benar khawatir tentang pemformatan keluaran, Anda dapat menggunakan DecimalFormat(seperti dalam new DecimalFormat("###.00")) untuk mengelola konversi BigDecimalkembali ke string. Ini memberikan "101.00"hasil untuk kedua nilai yang cuplikan dari @Grodriquez dan Anda buat.
joel.neely
3
Kali kedua Anda membulatkan di sini tidak diperlukan karena Anda tahu Anda sudah memiliki bilangan bulat, jadi saya akan menggunakan BigDecimal.ROUND_UNNECESSARY sebagai gantinya, sedikit lebih jelas menurut saya.
kosmoplan
5

Inilah solusi yang sangat rumit, tetapi berhasil:

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

Kode Tes:

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

Keluaran:

100
100
101
101

Sean Patrick Floyd
sumber
Bukan untuk mendukung solusi ini atau apa pun, tetapi input.toBigInteger().toString().length()bagian tersebut akan jauh lebih efisien dengan menggunakan logaritma, beberapa hal sepertiround_up(log(input)) + (1 if input is a power of ten, else 0)
Addison
0

Saya tidak berpikir Anda bisa membulatkannya seperti itu dalam satu perintah. Mencoba

    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

Saya menguji sisa contoh Anda dan mengembalikan nilai yang diinginkan, tetapi saya tidak menjamin kebenarannya.

Daniel Fath
sumber
-2

Kamu ingin

round(new MathContext(0));  // or perhaps another math context with rounding mode HALF_UP
jacobm
sumber
2
Ini tidak melakukan apa-apa. Dari dokumentasi round: "Jika pengaturan presisi adalah 0 maka tidak ada pembulatan."
Grodriguez