Seberapa acak Math.random JavaScript?

116

Selama 6 tahun saya memiliki halaman generator nomor acak di situs saya. Untuk waktu yang lama, ini adalah hasil pertama atau kedua di Google untuk "pembuat angka acak" dan telah digunakan untuk menentukan lusinan, jika bukan ratusan kontes dan gambar di forum diskusi dan blog (saya tahu karena saya melihat perujuk di log web dan biasanya pergi melihat-lihat).

Hari ini, seseorang mengirimi saya email untuk memberi tahu saya bahwa itu mungkin tidak seacak yang saya kira. Dia mencoba menghasilkan angka acak yang sangat besar (misalnya, antara 1 dan 1000000000000000000000) dan menemukan bahwa angka tersebut hampir selalu sama. Memang, saya membungkus fungsi dalam satu lingkaran sehingga saya bisa menghasilkan ribuan angka dan benar saja, untuk angka yang sangat besar, variasinya hanya sekitar 2 kali lipat.

Mengapa?

Ini adalah versi perulangannya, jadi Anda bisa mencobanya sendiri:

http://andrew.hedges.name/experiments/random/randomness.html

Ini mencakup implementasi langsung yang diambil dari Jaringan Pengembang Mozilla dan beberapa kode dari 1997 yang saya sapu dari halaman web yang tidak lagi ada ("Central Randomizer 1.3" dari Paul Houle). Lihat sumber untuk mengetahui cara kerja setiap metode.

Saya telah membaca di sini dan di tempat lain tentang Mersenne Twister. Yang saya minati adalah mengapa tidak akan ada variasi yang lebih besar dalam hasil dari fungsi Math.random bawaan JavaScript . Terima kasih!

Andrew Hedges
sumber
"sarnath'd" seperti dalam, dipukul sampai habis, atau dalam hal ini, jawabannya
maetl
5
Jika Anda mencari jawaban atas pertanyaan di judul, lihat stackoverflow.com/questions/2344312/…
Andrew B.

Jawaban:

182

Nomor yang diberikan antara 1 dan 100.

  • 9 memiliki 1 digit (1-9)
  • 90 memiliki 2 digit (10-99)
  • 1 memiliki 3 digit (100)

Nomor yang diberikan antara 1 dan 1000.

  • 9 memiliki 1 digit
  • 90 memiliki 2 digit
  • 900 memiliki 3 digit
  • 1 memiliki 4 digit

dan seterusnya.

Jadi jika Anda memilih beberapa secara acak, maka sebagian besar nomor yang dipilih akan memiliki jumlah digit yang sama, karena sebagian besar kemungkinan nilai memiliki jumlah digit yang sama.

Quentin
sumber
11
Ide Anda tentang keacakan yang berarti sempurna dan terdistribusi secara merata menarik ...
19
@ R.Pate - pembuatan bilangan acak tidak banyak berguna kecuali jika didistribusikan secara merata dalam skala panjang
annakata
3
Baca lagi. @David hanya menyebutkan angka apa saja yang ada di antara batas, bukan hasil pemilihan N angka acak. Saya mengakui bahwa judulnya menyesatkan.
nikc.org
3
Sebagai catatan, saya memilih jawaban ini dan @ jwoolard. Saya memilih yang ini sebagai jawaban yang diterima karena contoh-contohnya membuatnya sangat jelas mengapa distribusi angka condong ke angka dengan lebih banyak digit.
Andrew Hedges
1
@ andrew-hedges benar - ini adalah jawaban yang lebih jelas, tapi terima kasih :)
jwoolard
56

Hasil Anda benar-benar diharapkan. Jika bilangan acak didistribusikan secara seragam dalam rentang 1 hingga 10 ^ n, maka Anda akan mengharapkan sekitar 9/10 dari bilangan tersebut memiliki n digit, dan 9/100 selanjutnya memiliki n-1 digit.

jwoolard.dll
sumber
8
Persis. Distribusi jumlah digit diharapkan akan miring. Namun, distribusi log dari jumlah digit harus seragam.
Noldorin
45

Ada berbagai jenis keacakan. Math.random memberi Anda distribusi angka yang seragam.

Jika Anda menginginkan urutan besaran yang berbeda, saya sarankan untuk menggunakan fungsi eksponensial untuk membuat apa yang disebut distribusi hukum pangkat :

function random_powerlaw(mini, maxi) {
    return Math.ceil(Math.exp(Math.random()*(Math.log(maxi)-Math.log(mini)))*mini)
}

Fungsi ini akan memberi Anda jumlah angka 1 digit yang kira-kira sama dengan angka 2 digit dan sebagai angka 3 digit.

Ada juga distribusi lain untuk bilangan acak seperti distribusi normal (disebut juga distribusi Gaussian).

Kristen
sumber
Dengan algoritma ini, saya meletakkan minimum = 1dan maximum = 10dan terkadang mendapatkan 11 sebagai hasilnya. Anda mungkin bermaksud untuk menggunakan Math.flooralih-alihMath.round
Sam Eaton
1
Mengapa ini berhasil? Apakah itu mengubah distribusi seragam menjadi distribusi eksponensial?
shinzou
@shinzou Saya bertanya di math.stackexchange dan mendapatkan rumus yang sedikit berbeda sebagai jawabannya. Saya mengubah kode untuk mencerminkan rumus yang diturunkan secara matematis dari math.stackexchange.
Christian
20

Tampak sangat acak bagi saya! (Petunjuk: Ini tergantung browser.)

Secara pribadi, saya pikir implementasi saya akan lebih baik, meskipun saya mencurinya dari XKCD , yang harus SELALU diakui:

function random() {
  return 4; // Chosen by a fair dice throw. Guaranteed to be random.
}
Arafangion
sumber
19
1 untuk menyebutkan ketergantungan perambannya, -1 untuk meminjam xkcd tanpa menautkan.
Wajib atau tidak, karena ini xkcd, ini akan diatribusikan. :)
Arafangion
2
OT: Saya terkejut dan senang bahwa "XKCD" adalah jawaban untuk pertanyaan University Challenge minggu ini: D
Matt Sach
2
Bergi: Tautan langsung tidak cukup?
Arafangion
Saya pikir maksudnya lelucon itu tidak dikutip dengan benar ("random = 4;" bukannya "return 4;")
Eren Tantekin
18

Makalah berikut menjelaskan bagaimana math.random () di browser Web utama (tidak) aman: "Pelacakan pengguna sementara di browser utama serta kebocoran dan serangan informasi lintas domain" oleh Amid Klein (2008) . Ini tidak lebih kuat dari fungsi PRNG bawaan Java atau Windows.

Di sisi lain, penerapan SFMT periode 2 ^ 19937-1 membutuhkan 2496 byte dari keadaan internal yang dipertahankan untuk setiap urutan PRNG. Beberapa orang mungkin menganggap ini sebagai biaya yang tidak termaafkan.

jj1bdx.dll
sumber
1
+1: Makalah yang disebutkan itu bagus, jauh melampaui pertanyaan aslinya.
Roland Illig
6

Jika Anda menggunakan angka seperti 1000000000000000000000 Anda melampaui akurasi dari tipe data yang digunakan Javascript. Perhatikan bahwa semua angka yang dihasilkan diakhiri dengan "00".

Greg
sumber
1
Tapi itu bukan masalahnya dalam kasus ini.
Joey
3
@Johannes - itu salah satu masalahnya :)
annakata
Distribusi IEE754 tidak merata. Mungkin Anda dapat merepresentasikan 0 hingga 999 dalam kelipatan dua dan memiliki cukup presisi untuk itu sehingga Anda melihat distribusi yang merata di seluruh rentang tersebut jika Anda memilih angka berkali-kali. 10% akan menjadi dua digit dan 90% tiga digit. Namun, ketika Anda mulai mencapai angka yang sangat tinggi, kenaikannya akan melebihi 1. Anda mungkin hanya dapat melangkah dari satu triliun miliar menjadi satu triliun miliar seribu dan bukan satu triliun miliar satu. Meskipun untuk angka / skala kecil, efek ini dapat diabaikan hingga tidak ada. Efek skala akan memiliki dampak yang jauh lebih besar.
jgmjgm
5

Saya mencoba generator nomor pseudorandom JS di Chaos Game .

Segitiga Sierpiński saya mengatakan ini sangat acak: Fraktal

zie1ony
sumber
2
Maukah Anda membagikan kode segitiga di sini dan jsfiddle / jsbin sehingga kami dapat dengan mudah memeriksanya dalam praktik untuk browser yang berbeda?
Fabrício Matté
1
Oke, tapi beri saya waktu beberapa hari, karena saya perlu menerjemahkan kode ke bahasa Inggris. Sekarang bahasa Polandia-bahasa Inggris dan saya memiliki banyak pekerjaan.
zie1ony
1
@ zie1ony beberapa hari sudah habis.
trusktr
1
usp :( kerja, kerja, kerja Link: kubaplas.vot.pl/green/fractal Parameter pertama adalah nr simpul. Yang kedua adalah titik perpotongan (dari 0 ke 1) ruas garis. Coba saja.
zie1ony
4
Tautan mati - mungkin repo Github sebagai gantinya?
Mark K Cowan
3

Nah, jika Anda menghasilkan angka hingga, katakanlah, 1e6, Anda diharapkan mendapatkan semua angka dengan probabilitas yang kira-kira sama. Itu juga berarti bahwa Anda hanya memiliki satu dari sepuluh peluang untuk mendapatkan nomor dengan satu digit lebih sedikit. Kemungkinan satu dari seratus untuk mendapatkan dua digit lebih sedikit, dll. Saya ragu Anda akan melihat banyak perbedaan saat menggunakan RNG lain, karena Anda memiliki distribusi yang seragam di seluruh angka, bukan logaritmanya.

Joey
sumber
0

Bilangan non-acak yang didistribusikan secara seragam dari 1 ke N memiliki sifat yang sama. Perhatikan bahwa (dalam arti tertentu) ini masalah presisi. Distribusi seragam pada 0-99 (sebagai bilangan bulat) memang memiliki 90% bilangannya memiliki dua digit. Distribusi seragam pada 0-999999 memiliki 905 nomornya yang memiliki lima digit.

Setiap rangkaian angka (dalam beberapa kondisi yang tidak terlalu membatasi) memiliki kepadatan. Ketika seseorang ingin membahas bilangan "acak", kerapatan bilangan-bilangan ini harus ditentukan (seperti disebutkan di atas.) Kepadatan yang sama adalah kerapatan seragam. Ada yang lain: kepadatan eksponensial, kepadatan normal, dll. Seseorang harus memilih kepadatan mana yang relevan sebelum mengusulkan generator bilangan acak. Selain itu, angka yang berasal dari satu kepadatan seringkali dapat dengan mudah diubah ke kepadatan lain dengan cara karies.

ttw
sumber