Home > programming > [0.1 + 0.2 != 0.3] misteri floating point..!!

[0.1 + 0.2 != 0.3] misteri floating point..!!


float

Berapa hasil penjumlahan 0.1 + 0.2?  Sudah pasti jawabannya 0.3. Lalu bila kita ingin membandingkan apakah 0.1 + 0.2 = 0.3?  Jawabannya juga sudah tidak diragukan lagi, pasti “sama”. Tapi pernahkah kita benar-benar mencoba membuat program untuk membandingkan hasi kalkulasi seperti ini? Apa benar jawabannya adalah “sama”? ternyata tidak selalu jawabannya adalah sama.. 😐

Mungkin bagi yang pernah buat program yang memproses bilangan desimal (pecahan) pernah mengalami kegalauan saat hasil kalkulasi yang seharusnya benar malah menunjukkan keanehan, mmm.. okey mungkin tidak semua orang pernah melakukan kesalahan ini, paling tidak dulu saya pernah mengalami.. 😀

Contohnya begini, misalnya kita memiliki suatu program yang melakukan penjumlahan terhadap dua bilangan yang bertipe floating point, dalam C# kurang lebih kayak gini:

double a,b,c;
a=0.1;
b=0.2;
c=0.3;
if (a+b==c) {
Console.WriteLine(“benar”);
} else {
Console.WriteLine(“salah”);
}

Dari cuplikan program di atas (jangan liat kalo ada kesalahan syntax ya, program di atas belum pernah dicompile :D) nilai yang mau dijumlahkan adalah 0.1 + 0.2.
Berdasarakan kalkulasi sederhana yang kita pelajari di bangku sekolah, seharusnya hasilnya adalah 0.3.
Tapi begitu program ini dijalankan, maka hasil yang keluar adalah “salah”. kenapa bisa demikian?

Penjelasannya adalah karena kita menggunakan komputer yang bekerja dengan mengenali semua bilangan sebagai bilangan biner. apa itu bilangan biner? singkatnya adalah bilangan yang hanya terdiri dari angka 0 dan angka 1. lantas apa hubungannya dengan penjumlahan ini?

Baiklah, singkatnya dalam biner kita mengenal 0 sebagai 0 dan 1 sebagai 1 (ya iyalah.. :D). Lalu bagai mana dengan angka 2? 2 dalam biner ditulis dalam bentuk 10, 3 menjadi 11, kemudian 4 menjadi 100, dan 5 menjadi 101, dan seterusnya. Sampai di sini sudah agak bingung? gapapa, saya juga kok.

Tadi itu adalah konversi bilangan bulat ke biner. Lalu bagaimana dengan bilangan pecahan? Pecahan dalam biner tidak sama dengan bilangan bulat, kita tidak bisa menuliskan pecahan 0.2 menjadi 0.10 dalam biner karena bukan begitu cara kerjanya.Jadi bagaimana yang benar?
dalam biner, pecahan yang dikenal hanya yang kelipatan 2 yaitu:

1/2  =       (0.5) -> dalam biner (0.1) 1 bit,
1/4  =      (0.25) -> dalam biner (0.01) 2 bits,
1/8  =     (0.125) -> dalam biner (0.001) 3 bits,
1/16 =    (0.0625) -> dalam biner (0.0001) 4 bits,
1/32 =   (0.03125) -> dalam biner (0.00001) 5 bits,
1/64 =  (0.015625) -> dalam biner (0.000001) 6 bits,
1/128= (0.0078125) -> dalam biner (0.0000001) 7 bits,
1/256=(0.00390625) -> dalam biner (0.00000001) 8 bits, … dan seterusnya.

di situ saya menuliskan bits, itu adalah jumlah digit yang bisa kita gunakan yang juga mengindikasikan tingkat presisi yang diinginkan. Semakin besar bits semakin besar pula ukuran yang diperlukan di dalam memory komputer dalam menyimpan atau memprosesnya.

Dari contoh di atas kita lihat, tidak ada 0.1 ataupun 0.2. Lalu bagaimana mendapatkan nilai tersebut? Jawabannya adalah dengan melakukan proses aritmatik terhadap bilangan-bilangan biner ini. Misalnya untuk pecahan (desimal) 0.1 yang ingin kita konversi ke biner dengan presisi 8 bits (paling kecil 1/256):

  • Bisa kita dekati dengan penjumlahan 1/16 + 1/32 + 1/64 yaitu 0.09765625.
  • Atau dengan penjumlahan 1/16 + 1/32 + 1/128 yaitu 0.1015625

Nah, yang mana yang akan dipilih sebagai perwakilan 0.1? Prosedur konversi biner ini menghitung dari bilangan terkecil yang ditambahkan terus menerus sehingga memenuhi target yang ditetapkan, dalam hal ini adalah 0.1. Maka pada saat angka mencapai 0.09765625 komputer akan terus menghitung karena belum sampai pada 0.1. Dan pada saat mencapai angka 0.1015625 (penghitungan setelah angka 0.09765625  tadi) maka kondisi 0.1 sudah terpenuhi. Proses penghitungan stop dan nilai terakhir yang digunakan adalah 0.1015625.

Dalam biner, bilangan 0.1015625 ini ditulis sebagai 0.00011010 (persis 8 bits, 8 digit di belakang koma). Bilangan inilah yang disimpan di dalam komputer kita sebagai perwakilan dari bilangan 0.1 (desimal).

Dengan pemahaman yang sama kita mendapati 0.2 (desimal) dalam 8 bits biner akan dikenali sebagai 0.00110100 dalam biner (1/8 + 1/16 + 1/64 = 0.203125).

Lalu komputer akan menjumlahkan 0.00011010 + 0.00110100 = 0.1001110
Kalau hasil penjumlahan ini kita konversi lagi ke desimal, maka hasilnya menjadi 0.3046875.

Kalau begini sekilas saja bisa kita lihat bahwa 0.3 != 0.30078125 kan??
Tapi belum selesai coy 🙂
Sebenarnya yang terjadi di komputer adalah dengan membandingkan nilai binernya.
Dengan logika yang sama kita akan mendapatkan konversi 0.3 menjadi 0.01001101.
Sedangkan hasil penjumlahan yag kita dapat sebelumnya dari 0.1+0.2 adalah 0.1001110.
Sekarang kita bisa membandingkan bahwa 0.1001110 != 0.01001101 🙂

mistery solved!!

bonus:
Cara gampang mengkonversi pecahan(desimal) ke biner adalah dengan mengalikannya dengan angka 2 lalu mengambil angka di depan koma sebagai bilangan binernya. bila hasil perkalian belum sama dengan 1, maka ulangi terus perkaliannya.
Bila mendapatkan angka lebih dari 1 maka kurangi dulu dengan angka 1, lalu ulangi mengalikan hasil yang tadi dengan 2 sampai kita mendapatkan hasil angka 1 atau sampai ke perulangan perkalian sejumlah tingkat presisi tertentu yang diinginkan.
Bila pada pengalian terakhir (dengan tingkat presisi tertentu yang diinginkan) hasilnya bukan 1, maka ditambahkan angka 1 di digit paling kanan (untuk 8 bit berarti tambahkan 0.00000001)

misalnya 0.1 kita akan ambil 8 digit presisi:

0.1 * 2 = 0.2 -> ambil angka 0
0.2 * 2 = 0.4 -> ambil angka 0
0.4 * 2 = 0.8 -> ambil angka 0
0.8 * 2 = 1.6 -> ambil angka 1, lalu kurangi 1 jadi 0.6
0.6 * 2 = 1.2 -> ambil angka 1, lalu kurangi 1 jadi 0.2
0.2 * 2 = 0.4 -> ambil angka 0
0.4 * 2 = 0.8 -> ambil angka 0
0.8 * 2 = 1.6 -> ambil angka 1, hasil terakhir bukan 1 (1.6) maka bilangan biner ditambah 1 di paling kanan (0.00000001)

hasilnya adalah dengan menyusun angka yang kita ambil tadi menjadi

0.00011001 + 0.00000001 = 0.00011010

untuk 0.2 kita akan ambil 8 digit presisi:

0.2 * 2 = 0.4 -> ambil angka 0
0.4 * 2 = 0.8 -> ambil angka 0
0.8 * 2 = 1.6 -> ambil angka 1, lalu kurangi 1 jadi 0.6
0.6 * 2 = 1.2 -> ambil angka 1, lalu kurangi 1 jadi 0.2
0.2 * 2 = 0.4 -> ambil angka 0
0.4 * 2 = 0.8 -> ambil angka 0
0.8 * 2 = 1.6 -> ambil angka 1, lalu kurangi 1 jadi 0.6
0.6 * 2 = 1.2 -> ambil angka 1, hasil terakhir bukan 1 (1.2) maka bilangan biner ditambah 1 di paling kanan (0.00000001)

hasilnya adalah dengan menyusun angka yang kita ambil tadi menjadi

0.00110011 + 0.00000001 = 0.00110100

Bagaimana, sama kan hasilnya kalau dibandingkan penghitungan dengan cara sebelumnya? 🙂

NB lagi: sekedar catetan aja bagi yang belum pernah nyobain yang beginian, sebenarnya tidak semua penjumlahan dalam floating point akan menghasilkan kekeliruan.
Misalnya bila kita menjumlahkan 0.1 + 0.1 hasilnya adalah benar 0.2.
Karena bila kita berpedoman dengan angka di atas tadi 0.1 adalah 0.00011010 sedangkan 0.2 adalah 0.00110100. Dan 0.00011010 + 0.00011010 = 0.00110100.
Coba aja jumlahin bilangan binernya, hasilnya sama kok 🙂

referensi:
konverter desimal – binary online: http://www.exploringbinary.com/binary-converter/
interpreter C# online: http://rextester.com/
kalkulator binary: aplikasi Calculator bawaan Windows 😀

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: