author-pic

Ferry S

An ISTJ, Type 5, Engineer, Gamer, and Thriller-Movies-Lover
Java: BigDecimal vs Double
Thursday Dec 15th, 2022 09:05 pm6 mins read
Java, Tips & Tutorial
Java: BigDecimal vs Double
Source: Adobe - Understanding Decimals

Ketika mengembangkan aplikasi, melakukan kalkulasi bilangan desimal terkadang cukup tricky. Apalagi kalau berhubungan dengan duit, seperti pada aplikasi perbankan, e-commerce, dan sejenisnya. Perhitungannya tentu harus akurat sesuai aturan yang diberlakukan oleh perusahaan. Kalau tidak teliti saat develop bisa salah perhitungannya. Salah satu hal yang dipertimbangkan saat develop adalah penggunaan tipe data. Seperti pada Java, ada dua tipe data yang bisa digunakan untuk menampung bilangan desimal dengan ukuran yang besar, yaitu BigDecimal dan Double. Walaupun sama-sama bisa menampung bilangan desimal dengan ukuran besar, keduanya memiliki perbedaan yang cukup signifikan.

Native

Kita bisa menggunakan Double secara native tanpa perlu bikin objek. Sedangkan BigDecimal adalah objek khusus pada Java. Kita butuh inisiasi objek dan membungkus angka ke dalamnya terlebih dahulu sebelum menggunakannya. Termasuk saat melakukan kalkulasi, pada Double kita bisa langsung menggunakan operator matematika. Sedangkan untuk BigDecimal kita hanya bisa melakukannya lewat method yang terdapat pada BigDecimal. Contohnya seperti berikut:

double d = 0.1;
double dd = 0.5 + 0.3 - 0.1 * 4 / 2;

BigDecimal bigDecimal = BigDecimal.valueOf(0.1);
BigDecimal bigDecimal1 = BigDecimal.valueOf(0.5)
		.add(BigDecimal.valueOf(0.3))
		.subtract(BigDecimal.valueOf(0.1)
				.multiply(BigDecimal.valueOf(4)
						.divide(BigDecimal.valueOf(2), RoundingMode.HALF_EVEN)));

Oh ya, perlu diperhatikan ketika menggunakan BigDecimal, urutan kalkulasinya tidak seperti standar matematika, melainkan dari paling kiri ke kanan, kecuali ada perhitungan di dalam tanda kurung. Sedangkan pada Double, urutan kalkulasinya sesuai standar matematika, yaitu perkalian/pembagian terlebih dahulu, baru setelah itu penjumlahan/pengurangan, kecuali ada perhitungan di dalam tanda kurung.

Calculation

Pada Double kalkulasi yang digunakan menggunakan system floating point yang dihitung secara binary. Contohnya ketika melakukan kalkulasi 0.1 + 0.2 maka hasilnya adalah 0.30000000000000004. Sedangkan secara akuntansi, 0.1 + 0.2 hasilnya adalah 0.3 seharusnya. Kalau kita menggunakannya pada use case yang berhubungan dengan perhitungan uang, tentu sangat tricky. Apalagi pada perbankan, beda sedikit saja, walaupun hanya selisih satu angka dibelakang koma, hasil kalkulasinya tentu sangat berdampak pada bisnis perusahaan. Tapi kalau kita menggunakan BigDecimal, hasilnya adalah 0.3 sesuai dengan yang kita harapkan.

double x = 0.1;
double y = 0.2;
System.out.println("(x + y) = " + (x + y));

BigDecimal a = BigDecimal.valueOf(0.1);
BigDecimal b = BigDecimal.valueOf(0.2);
System.out.println("a.add(b) = " + a.add(b));

Scale

Pada BigDecimal kita bisa tentukan scale atau jumlah digit desimalnya sesuai yang kita mau saat digunakan. Ketika melakukan perhitungan, scale pada BigDecimal adalah tak terhingga. Makanya kita disarankan menentukan scale dan rounding pada saat melakukan pembagian untuk menghindari scale tak terhingga yang mengakibatkan error ArithmeticException. Contohnya ketika membagi 10 dibagi 3 yang menghasilkan angka desimal tak terhingga. Sedangkan pada Double kita tidak bisa langsung menentukan scale, kita hanya bisa melakukan pembulatan ketika dikonversi ke String menggunakan DecimalFormat. Atau dengan convert menjadi BigDecimal lalu set scale dan convert lagi ke Double. Pada saat melakukan pembagian 10 dibagi 3 menggunakan Double tidak akan error, tapi akan otomatis melakukan pembulatan menggunakan system floating point.

Rounding

By default, RoundingMode yang digunakan pada Double adalah Half Even. Kita hanya bisa mengubahnya menggunakan bantuan objek DecimalFormat saat convert ke String. Sedangkan pada BigDecimal by default RoundingMode-nya adalah Unnecessary. Tapi kita bisa mengubah RoundingMode yang diinginkan secara langsung pada objeknya. Makanya, saat melakukan pembagian, selain menentukan scale kita juga disarankan menentukan RoundingMode yang diinginkan pada parameter untuk mencegah ArithmeticException. RoundingMode sangat penting pada bisnis perusahaan yang memiliki rules tertentu terutama saat melakukan pembulatan. Misalnya saat melakukan kalkulasi diskon, perusahaan tersebut memiliki kebijakan melakukan pembulatan terlebih dahulu sebelum melakukan perkalian/pembagian dengan RoundingMode tertentu.

Terdapat 6 jenis RoundingMode yang bisa digunakan.

RoundingMode Ceiling

Secara gampangnya, pembulatannya selalu mendekati ke arah yang lebih positif. Contohnya bilangan 0.563 dengan scale 2 angka di belakang koma menggunakan RoundingMode Ceiling, maka hasilnya adalah 0.57. Sedangkan untuk bilangan negatif, -0.563, maka hasilnya adalah -0.56 karena -0.56 lebih mendekati ke arah positif daripada -0.57.

RoundingMode Floor

Ini adalah kebalikan dari RoundingMode Ceiling, kalau RoundingMode Floor pembulatannya selalu mendekati ke arah yang lebih negatif. Contohnya bilangan 0.567 dengan scale 2 angka di belakang koma menggunakan RoundingMode Floor, maka hasilnya adalah 0.56. Sedangkan untuk bilangan negatif, -0.567, maka hasilnya adalah -0.57 karena -0.57 lebih mendekati ke arah negatif daripada -0.56.

RoundingMode Up

RoundingMode Up adalah pembulatannya menjauhi 0. Contohnya bilangan 0.563 dengan scale 2 angka di belakang koma menggunakan RoundingMode Up, maka hasilnya adalah 0.57. Begitu juga dengan bilangan negatif, -0.563, maka hasilnya adalah -0.57 karena -0.57 lebih jauh dari angka 0 dibanding -0.56.

RoundingMode Down

RoundingMode Down kebalikannya RoundingMode Up, yaitu pembulatannya mendekati 0. Contohnya bilangan 0.567 dengan scale 2 angka di belakang koma menggunakan RoundingMode Down, maka hasilnya adalah 0.56. Begitu juga dengan bilangan negatif, -0.567, maka hasilnya adalah -0.56 karena -0.56 lebih mendekati 0 daripada -0.57.

RoundingMode Half Up

Pada RoundingMode Up, pembulatannya selalu menjauhi 0 berapapun bilangan terakhirnya. Sedangkan untuk RoundingMode Half Up, jika angka pembulatan terakhirnya rentang 1-4 maka pembulatannya mendekati 0, untuk angka pembulatan terakhirnya rentang 6-9 maka pembulatannya menjauhi 0. Sedangkan untuk angka pembulatan terakhirnya 5, maka pembulatannya menjauhi 0. Contohnya pada tabel berikut menggunakan scale 2 digit:

Number Rounding Result
0.567 0.57
0.563 0.56
0.565 0.57
-0.565 -0.57
-0.563 -0.56
-0.567 -0.57

RoundingMode Half Down

Untuk RoundingMode Half Down, jika angka pembulatan terakhirnya rentang 1-4 maka pembulatannya mendekati 0, untuk angka pembulatan terakhirnya rentang 6-9 maka pembulatannya menjauhi 0. Sedangkan untuk angka pembulatan terakhirnya 5, maka pembulatannya mendekati 0. Contohnya pada tabel berikut menggunakan scale 2 digit:

Number Rounding Result
0.567 0.57
0.563 0.56
0.565 0.56
-0.565 -0.56
-0.563 -0.56
-0.567 -0.57

RoundingMode Half Even

Ini juga sama seperti kedua RoundingMode Half sebelumnya, untuk angka pembulatan terakhirnya rentang 1-4 pembulatannya mendekati 0 dan untuk rentang 6-9 pembulatannya menjauhi 0. Yang membedakan adalah ketika angka pembulatan terakhirnya 5, maka pembulatannya menjadi angka genap. Contohnya 0.565, maka pembulatannya ke bawah menjadi 0.56 karena itu adalah bilangan genap. Sedangkan untuk bilangan 0.575, maka pembulatannya digenapkan ke atas menjadi 0.58. Ini adalah RoundingMode yang umum digunakan perbankan untuk mengolah data keuangan.

Number Rounding Result
0.567 0.57
0.563 0.56
0.565 0.56
0.575 0.58
-0.575 -0.58
-0.565 -0.56
-0.563 -0.56
-0.567 -0.57

RoundingMode Unnecessary

Unnecessary artinya tidak ada pembulatan sama sekali. Ini harus dihindari, apalagi saat melakukan pembagian karena dapat menghasilkan error ArithmeticException. Ini adalah default rounding dari BigDecimal, makanya ketika melakukan pembagian menggunakan BigDecimal kita disarankan menentukan scale dan rounding pada method divide untuk menghindari Hasil yang tidak diinginkan.

Verdict

Itulah beberapa perbedaan BigDecimal dengan Double. BigDecimal memiliki fitur yang lebih advanced dibanding Double karena kita bisa menentukan scale dan rounding yang diinginkan sesuai kebutuhan bisnis. Ketika melakukan pembagian menggunakan BigDecimal, kita wajib menentukan RoundingMode dan scale untuk menghindari ArithmeticException karena default RoundingMode-nya adalah Unnecessary dan default scale-nya adalah tak terhingga. Juga perlu diperhatikan, urutan kalkulasi pada BigDecimal adalah dari yang paling kiri atau sesuai tanda kurung, bukan mengikuti standar matematika seperti Double. Secara penggunaan, BigDecimal lebih kompleks daripada Double karena merupakan objek khusus pada Java, kita harus membungkus setiap angka yang ingin dihitung menjadi BigDecimal dan menggunakan method yang ada di dalamnya untuk melakukan kalkulasi. Berbeda dengan Double yang lebih gampang digunakan menggunakan operator matematika biasa. Secara penggunaan, BigDecimal sangat cocok untuk perhitungan akuntansi seperti hal-hal yang berkaitan dengan keuangan. Sedangkan Double lebih cocok untuk hal-hal umum lainnya yang ga perlu angka desimal dengan presisi yang akurat seperti menghitung berat volume.