Saya harus menghitung beberapa variabel floating point dan kolega saya menyarankan saya untuk menggunakan BigDecimalalih-alih doublekarena akan lebih tepat. Tapi saya ingin tahu apa itu dan bagaimana memanfaatkannya BigDecimal?
Saya harus menghitung beberapa variabel floating point dan kolega saya menyarankan saya untuk menggunakan BigDecimalalih-alih doublekarena akan lebih tepat. Tapi saya ingin tahu apa itu dan bagaimana memanfaatkannya BigDecimal?
Jawaban:
A BigDecimaladalah cara yang tepat untuk merepresentasikan angka. A Doublememiliki presisi tertentu. Bekerja dengan dobel dari berbagai besaran (katakan d1=1000.0dan d2=0.001) dapat mengakibatkan 0.001dijatuhkan secara bersamaan ketika dijumlahkan karena perbedaan besarnya sangat besar. Dengan BigDecimalini tidak akan terjadi.
Kerugiannya BigDecimaladalah bahwa itu lebih lambat, dan itu sedikit lebih sulit untuk memprogram algoritma seperti itu (karena + - *dan /tidak kelebihan beban).
Jika Anda berurusan dengan uang, atau ketepatan adalah suatu keharusan, gunakan BigDecimal. Kalau tidak, Doublescenderung cukup baik.
Saya sarankan membaca javadoc dari BigDecimalseperti yang mereka lakukan menjelaskan hal-hal yang lebih baik daripada yang saya lakukan di sini :)
if (Math.abs(loadPerServer - maxLoadPerServer) < 0.000001d) {
BigDecimal", Double akan memiliki lebih banyak "presisi" (lebih banyak digit).
Bahasa Inggris saya tidak bagus jadi saya hanya akan menulis contoh sederhana di sini.
double a = 0.02;
double b = 0.03;
double c = b - a;
System.out.println(c);
BigDecimal _a = new BigDecimal("0.02");
BigDecimal _b = new BigDecimal("0.03");
BigDecimal _c = _b.subtract(_a);
System.out.println(_c);
Output program:
0.009999999999999998
0.01
Adakah yang masih ingin menggunakan dobel? ;)
System.out.println(0.003f - 0.002f);BigDecimal tepat:System.out.println(new BigDecimal("0.003").subtract(new BigDecimal("0.002")));
Ada dua perbedaan utama dari ganda:
Alasan Anda harus menggunakan BigDecimal untuk perhitungan moneter bukan karena ia dapat mewakili angka apa pun, tetapi ia dapat mewakili semua angka yang dapat direpresentasikan dalam konsep desimal dan yang mencakup hampir semua angka dalam dunia moneter (Anda tidak pernah mentransfer 1/3 $ untuk seseorang).
Jika Anda menuliskan nilai pecahan seperti 1 / 7nilai desimal yang Anda dapatkan
1/7 = 0.142857142857142857142857142857142857142857...
dengan urutan tak terbatas 142857. Karena Anda hanya dapat menulis jumlah digit terbatas, Anda pasti akan membuat kesalahan pembulatan (atau pemotongan).
Angka seperti 1/10atau 1/100dinyatakan sebagai angka biner dengan bagian fraksional juga memiliki jumlah digit tak terbatas setelah titik desimal:
1/10 = binary 0.0001100110011001100110011001100110...
Doubles menyimpan nilai-nilai sebagai biner dan karena itu dapat memperkenalkan kesalahan semata-mata dengan mengubah angka desimal menjadi angka biner, tanpa melakukan aritmatika apa pun.
Angka desimal (seperti BigDecimal), di sisi lain, menyimpan setiap angka desimal apa adanya. Ini berarti bahwa jenis desimal tidak lebih tepat daripada titik mengambang biner atau tipe titik tetap dalam arti umum (yaitu tidak dapat menyimpan 1/7tanpa kehilangan presisi), tetapi lebih akurat untuk angka yang memiliki jumlah terbatas angka desimal sebagai sering terjadi untuk perhitungan uang.
Jawa BigDecimalmemiliki keuntungan tambahan yang dapat memiliki sewenang-wenang (namun terbatas) jumlah digit di kedua sisi titik desimal, hanya dibatasi oleh memori yang tersedia.
BigDecimal adalah perpustakaan numerik presisi arbitrer Oracle. BigDecimal adalah bagian dari bahasa Jawa dan berguna untuk berbagai aplikasi mulai dari yang finansial hingga yang ilmiah (di situlah saya ada).
Tidak ada yang salah dengan menggunakan ganda untuk perhitungan tertentu. Misalkan, Anda ingin menghitung Math.Pi * Math.Pi / 6, yaitu, nilai Riemann Zeta Function untuk argumen nyata dua (proyek yang sedang saya kerjakan). Divisi floating-point memberi Anda masalah kesalahan pembulatan yang menyakitkan.
BigDecimal, di sisi lain, mencakup banyak opsi untuk menghitung ekspresi dengan ketepatan arbitrer. Metode tambah, gandakan, dan bagi seperti dijelaskan dalam dokumentasi Oracle di bawah ini "take the place" dari +, *, dan / di BigDecimal Java World:
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
Metode compareTo sangat berguna untuk while dan untuk loop.
Namun, berhati-hatilah dalam penggunaan konstruktor untuk BigDecimal. Konstruktor string sangat berguna dalam banyak kasus. Misalnya, kodenya
BigDecimal onethird = BigDecimal baru ("0.33333333333");
menggunakan representasi string 1/3 untuk mewakili nomor berulang berulang hingga tingkat akurasi yang ditentukan. Kesalahan pembulatan kemungkinan besar terjadi di suatu tempat yang jauh di dalam JVM sehingga kesalahan pembulatan tidak akan mengganggu sebagian besar perhitungan praktis Anda. Namun, dari pengalaman pribadi saya, saya melihat banyak hal. Metode setScale penting dalam hal ini, seperti yang dapat dilihat dari dokumentasi Oracle.
/* * Portions Copyright IBM Corporation, 2001. All Rights Reserved. */
Jika Anda berurusan dengan perhitungan, ada undang-undang tentang bagaimana Anda harus menghitung dan presisi apa yang harus Anda gunakan. Jika Anda gagal Anda akan melakukan sesuatu yang ilegal. Satu-satunya alasan sebenarnya adalah bahwa representasi bit dari kasus desimal tidak tepat. Seperti yang dikatakan Basil, sebuah contoh adalah penjelasan terbaik. Hanya untuk melengkapi contohnya, inilah yang terjadi:
static void theDoubleProblem1() {
double d1 = 0.3;
double d2 = 0.2;
System.out.println("Double:\t 0,3 - 0,2 = " + (d1 - d2));
float f1 = 0.3f;
float f2 = 0.2f;
System.out.println("Float:\t 0,3 - 0,2 = " + (f1 - f2));
BigDecimal bd1 = new BigDecimal("0.3");
BigDecimal bd2 = new BigDecimal("0.2");
System.out.println("BigDec:\t 0,3 - 0,2 = " + (bd1.subtract(bd2)));
}
Keluaran:
Double: 0,3 - 0,2 = 0.09999999999999998
Float: 0,3 - 0,2 = 0.10000001
BigDec: 0,3 - 0,2 = 0.1
Kami juga memiliki itu:
static void theDoubleProblem2() {
double d1 = 10;
double d2 = 3;
System.out.println("Double:\t 10 / 3 = " + (d1 / d2));
float f1 = 10f;
float f2 = 3f;
System.out.println("Float:\t 10 / 3 = " + (f1 / f2));
// Exception!
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4)));
}
Memberi kami hasilnya:
Double: 10 / 3 = 3.3333333333333335
Float: 10 / 3 = 3.3333333
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion
Tapi:
static void theDoubleProblem2() {
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4, 4, BigDecimal.ROUND_HALF_UP)));
}
Memiliki output:
BigDec: 10 / 3 = 3.3333