Permulaanya ketika saya membuat sebuah fungsi yang menggunakan javascript untuk menampilkan gambar secara random di halaman HTML. Ketika sudah selesai, tentu saja dicoba dengan cara alakadarnya, yaitu menampilkan halaman HTML tersebut berulang-ulang pada web browser, dan mengamati gambar yang muncul.
Setelah sekian kali diamati, ada sesuatu yang rasanya kurang pas. Gambar yang berada pada posisi pertama dan paling akhir dalam daftar gambar yang akan ditampilkan secara random tersebut, sangat jarang terpilih untuk tampil. Menurut perkiraan saya, semua gambar memiliki kesempatan yang sama untuk muncul. Jika misalnya ada 10 gambar, maka masing-masing mempunyai kesempatan untuk tampil adalah sebesar 10%. Tetapi dalam pengujian alakdarnya itu, dua gambar ini serasa "kurang diberi kesempatan" :-) Pasti ada sesuatu! Maka curigalah saya.
Dibuatlah sebuah program untuk meyakinkan, bahwa memang ada sesuatu dengan fungsi random yang dimiliki javascript. Program ini akan membuat bilangan random antara 1 sampai 10. Bilangan random dibuat sebanyak 10 ribu bilangan. Frekuensi kemunculan masing-masing bilangan dicatat, lalu ditampilkan. Lagi-lagi, sebelum melihat hasil program ini, menurut saya, setiap angka dari 1 sampai 10, memiliki persentase frekuensi kemunculan yang berdekatan. Tetapi ketika dijalankan, hasilnya memang tidak seperti harapan. Jadi terbukti bahwa memang ada "sesuatu" dengan fungsi random javascipt. Pengujian ini saya lakukan menggunakan 2 buah web browser, yaitu Firefox 2.0.0.18, dan Opera 9.62, pada Slackware 11. Kedua web browser menunjukkan hasil yang sama, yaitu angka 1 dan angka 10 hanya mendapat porsi sekitar setengah dari bilangan lainnya.
Namun, sebelum saya betul-betul merasa yakin dengan dugaan ini, ada satu lagi yang hampir saya lupakan. Bisa jadi, cara saya dalam menghasilkan bilangan random antara 1 sampai 10 yang sebenarnya punya masalah. Berikut ini adalah bagian yang digunakan untuk menghasilkan bilangan random. Mungkin bisa jadi, inilah sumber masalah itu. Tapi, rasanya bukan itu :-)
a = Math.round((Math.random() * 9) + 1);
Silahkan mencobanya melalui program yang saya sertakan dalam halaman ini. Klik pada tombol di bawah untuk membuat 10.000 angka random antara 1 sampai 10. Hasilnya akan langsung ditampilkan menggunakan grafik batang. Jika ingin mengulang, klik lagi pada tombol. Source code bisa langsung dilihat dengan cara melihat source halaman ini.
Setelah mendapat tanggapan dari rekan di mailing list PHP, fungsi round yang digunakan pada cara di atas, diganti dengan fungsi floor. Hasilnya, tidak ada lagi bilangan yang "dianaktirikan" :-) Semua bilangan mendapat kesempatan sama untuk muncul. Silahkan lihat pada bagian berikut.
Jika ditelusuri dengan baik, akan diperoleh di mana penyebabnya. fungsi Math.round() yang ada pada javascript adalah fungsi yang menghasilkan bilangan random antara 0 sampai 1, dalam bentuk pecahan. Dalam penggunaan secara umum, bilangan random yang diinginkan biasanya dalam bentuk bilangan bulat, misalnya antara 1 sampai 100. Bilangan yang dihasilkan oleh Math.round() tentu perlu dikalikan terlebih dahulu. Setelah dikalikan, karena masih dalam bentuk bilangan pecahan, diperlukan lagi proses pembulatan, agar diperoleh bilangan bulat. Pembulatan bisa dilakukan dengan tiga cara, yaitu floor untuk pembulatan ke bawah, ceil untuk pembulatan ke atas, dan round untuk pembulatan ke bilangan bulat terdekat.
Disinilah masalah itu timbul. Jika menggunakan round, maka bilangan terbawah dan tertinggi akan lebih sedikit muncul, dibanding bilangan yang berada di antara keduanya. Mari kita lihat ilustrasi berikut :
0----0.5----1----1.5----2----2.5----3----3.5----4----4.5----5 ______|___________|___________|___________|___________|______
Apabila dilakukan pembulatan, maka pembulatan yang akan menghasilkan bilangan 0 dan 5 kesempatannya lebih sedikit dibanding hasil pembulatan yang akan menghasilkan bilangan 1, 2, 3, atau 4. Pembulatan yang menghasilkan bilangan 0 hanyalah jika hasil random berada di rentang 0 sampai 0.5. Demikian juga pembulatan yang akan menghasilkan 5 jika bilangan random yang muncul adalah dari 4.5 sampai 5. Sedangkan, misal diambil contoh untuk hasil pembulatan menjadi 2, berada dalam rentang yang lebih luas, yaitu dari 1.5 sampai 2.5. Hal ini sudah cukup menjelaskan mengapa kemunculan bilangan terkecil dan terbesar lebih sedikit dibanding yang lainnya.
Sedangkan jika menggunakan fungsi floor, mari kita lihat ilustrasi berikut :
0--------1--------2--------3--------4--------5 ________|________|________|________|________|
Kesempatan untuk hasil pembulatan pada semua bilangan menjadi rata. Yang perlu diperhatikan adalah, batas atas perlu dilakukan penyesuaian. Misalnya jika akan mendapatkan bilangan random dari 1 sampai 100, bisa menggunakan rumus seperti berikut :
a = Math.floor((Math.random() * 100) + 1);
Terima kasih untuk tanggapan dari Siyam Junianto, dan Enggal Mandiri. Link berikut memberi penjelasan yang sama, menggunakan tabel yang lebih jelas http://imonky.com/j/randomjs.html