Pertanyaan Cara membulatkan angka ke n desimal di Jawa


Apa yang saya inginkan adalah metode untuk mengubah dobel menjadi string yang putaran menggunakan metode setengah-up - yaitu jika desimal yang dibulatkan adalah 5, itu selalu membulatkan ke angka sebelumnya. Ini adalah metode standar pembulatan yang diharapkan kebanyakan orang dalam kebanyakan situasi.

Saya juga ingin hanya digit yang signifikan untuk ditampilkan - yaitu tidak boleh ada nol di belakangnya.

Saya tahu satu metode untuk melakukan ini adalah dengan menggunakan String.format metode:

String.format("%.5g%n", 0.912385);

kembali:

0.91239

yang bagus, tetapi selalu menampilkan angka dengan 5 desimal meskipun tidak signifikan:

String.format("%.5g%n", 0.912300);

kembali:

0.91230

Metode lain adalah menggunakan DecimalFormatter:

DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);

kembali:

0.91238

Namun karena Anda dapat melihat ini menggunakan pembulatan setengah-bahkan. Itu akan membulatkan ke bawah jika digit sebelumnya genap. Apa yang saya suka adalah ini:

0.912385 -> 0.91239
0.912300 -> 0.9123

Apa cara terbaik untuk mencapai ini di Jawa?


1021
2017-09-30 16:01


asal


Jawaban:


Menggunakan setRoundingMode, mengatur RoundingMode secara eksplisit untuk menangani masalah Anda dengan putaran setengah putaran, lalu gunakan pola format untuk keluaran yang Anda inginkan.

Contoh:

DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.CEILING);
for (Number n : Arrays.asList(12, 123.12345, 0.23, 0.1, 2341234.212431324)) {
    Double d = n.doubleValue();
    System.out.println(df.format(d));
}

memberikan output:

12
123.1235
0.23
0.1
2341234.2125

583
2017-09-30 16:14



Asumsi value adalah double, Anda dapat melakukan:

(double)Math.round(value * 100000d) / 100000d

Itu untuk 5 digit presisi. Jumlah nol menunjukkan jumlah desimal.


397
2017-09-30 16:07



new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);

akan membuat Anda BigDecimal. Untuk mendapatkan string dari itu, sebut saja itu BigDecimal's toString metode, atau toPlainString metode untuk Java 5+ untuk string format biasa.

Program sampel:

package trials;
import java.math.BigDecimal;

public class Trials {

    public static void main(String[] args) {
        int yourScale = 10;
        System.out.println(BigDecimal.valueOf(0.42344534534553453453-0.42324534524553453453).setScale(yourScale, BigDecimal.ROUND_HALF_UP));
    }

164
2017-09-30 18:33



Anda juga bisa menggunakan

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);

untuk memastikan Anda memiliki 0 trailing.


98
2017-09-30 16:58



Seperti yang dicatat beberapa orang lain, jawaban yang benar adalah menggunakan keduanya DecimalFormat atau BigDecimal. Floating-point tidak memiliki tempat desimal sehingga Anda tidak mungkin membulatkan / memotong ke nomor tertentu dari mereka di tempat pertama. Anda harus bekerja dalam bentuk desimal, dan itulah yang dilakukan oleh kedua kelas tersebut.

Saya memposting kode berikut sebagai contoh tandingan untuk semua jawaban di utas ini dan memang di seluruh StackOverflow (dan di tempat lain) yang merekomendasikan perkalian diikuti dengan pemotongan diikuti oleh pembagian. Ini adalah kewajiban para pendukung teknik ini untuk menjelaskan mengapa kode berikut menghasilkan output yang salah di lebih dari 92% kasus.

public class RoundingCounterExample
{

    static float roundOff(float x, int position)
    {
        float a = x;
        double temp = Math.pow(10.0, position);
        a *= temp;
        a = Math.round(a);
        return (a / (float)temp);
    }

    public static void main(String[] args)
    {
        float a = roundOff(0.0009434f,3);
        System.out.println("a="+a+" (a % .001)="+(a % 0.001));
        int count = 0, errors = 0;
        for (double x = 0.0; x < 1; x += 0.0001)
        {
            count++;
            double d = x;
            int scale = 2;
            double factor = Math.pow(10, scale);
            d = Math.round(d * factor) / factor;
            if ((d % 0.01) != 0.0)
            {
                System.out.println(d + " " + (d % 0.01));
                errors++;
            }
        }
        System.out.println(count + " trials " + errors + " errors");
    }
}

Output dari program ini:

10001 trials 9251 errors

EDIT: Untuk mengatasi beberapa komentar di bawah saya redid bagian modulus dari loop uji menggunakan BigDecimal dan new MathContext(16) untuk operasi modulus sebagai berikut:

public static void main(String[] args)
{
    int count = 0, errors = 0;
    int scale = 2;
    double factor = Math.pow(10, scale);
    MathContext mc = new MathContext(16, RoundingMode.DOWN);
    for (double x = 0.0; x < 1; x += 0.0001)
    {
        count++;
        double d = x;
        d = Math.round(d * factor) / factor;
        BigDecimal bd = new BigDecimal(d, mc);
        bd = bd.remainder(new BigDecimal("0.01"), mc);
        if (bd.multiply(BigDecimal.valueOf(100)).remainder(BigDecimal.ONE, mc).compareTo(BigDecimal.ZERO) != 0)
        {
            System.out.println(d + " " + bd);
            errors++;
        }
    }
    System.out.println(count + " trials " + errors + " errors");
}

Hasil:

10001 trials 4401 errors

75
2017-10-02 03:18



Misalkan Anda punya

double d = 9232.129394d;

Kamu dapat memakai BigDecimal

BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN);
d = bd.doubleValue();

atau tanpa BigDecimal

d = Math.round(d*100)/100.0d;

dengan kedua solusi d == 9232.13


71
2018-01-28 09:52



Anda dapat menggunakan kelas DecimalFormat.

double d = 3.76628729;

DecimalFormat newFormat = new DecimalFormat("#.##");
double twoDecimal =  Double.valueOf(newFormat.format(d));

52
2017-09-29 07:01



Java yang Nyata How-to posting solusi ini, yang juga kompatibel untuk versi sebelum Java 1.6.

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();

34
2017-09-01 11:14