Apakah mungkin untuk menaburkan generator angka acak (Math.random) dalam Javascript?
javascript
random
menangis
sumber
sumber
Jawaban:
Tidak, tidak, tapi cukup mudah untuk menulis generator Anda sendiri, atau lebih baik menggunakan yang sudah ada. Lihat: pertanyaan terkait ini .
Juga, lihat blog David Bau untuk informasi lebih lanjut tentang penyemaian .
sumber
CATATAN: Meskipun (atau lebih tepatnya, karena) ringkas dan elegan, algoritma ini sama sekali tidak berkualitas tinggi dalam hal keacakan. Cari misalnya yang tercantum dalam jawaban ini untuk hasil yang lebih baik.
(Awalnya diadaptasi dari ide cerdas yang disajikan dalam komentar untuk jawaban lain.)
Anda dapat mengatur
seed
menjadi nomor apa saja, hindari saja nol (atau kelipatan Math.PI).Keanggunan solusi ini, menurut saya, berasal dari tidak adanya angka "ajaib" (selain 10.000, yang mewakili tentang jumlah minimum digit yang harus Anda buang untuk menghindari pola aneh - lihat hasil dengan nilai 10 , 100 , 1000 ). Keringkasan juga bagus.
Ini sedikit lebih lambat daripada Math.random () (dengan faktor 2 atau 3), tapi saya percaya ini tentang secepat solusi lain yang ditulis dalam JavaScript.
sumber
Saya telah mengimplementasikan sejumlah fungsi Pseudorandom number generator (PRNG) yang baik, pendek dan cepat dalam JavaScript biasa. Semuanya dapat diunggulkan dan memberikan angka kualitas yang baik.
Pertama-tama, berhati-hatilah untuk menginisialisasi PRNG Anda dengan benar. Sebagian besar generator di bawah ini tidak memiliki prosedur penghasil benih built-in (demi kesederhanaan), tetapi menerima satu atau lebih nilai 32-bit sebagai keadaan awal PRNG. Benih yang serupa (misalnya benih sederhana 1 dan 2) dapat menyebabkan korelasi pada PRNG yang lebih lemah, menghasilkan output yang memiliki sifat yang sama (seperti tingkat yang dihasilkan secara acak serupa). Untuk menghindari hal ini, praktik terbaik adalah menginisialisasi PRNG dengan benih yang didistribusikan dengan baik.
Untungnya, fungsi hash sangat baik dalam menghasilkan benih untuk PRNG dari string pendek. Fungsi hash yang baik akan menghasilkan hasil yang sangat berbeda bahkan ketika dua string serupa. Berikut ini contoh berdasarkan fungsi pencampuran MurmurHash3:
Setiap panggilan berikutnya ke fungsi kembali dari
xmur3
menghasilkan "acak" nilai hash 32-bit baru yang akan digunakan sebagai benih di PRNG a. Begini cara Anda menggunakannya:Atau, cukup pilih beberapa data dummy untuk mengisi benih, dan majukan generator beberapa kali (12-20 iterasi) untuk mencampur kondisi awal secara menyeluruh. Ini sering terlihat dalam implementasi referensi PRNG, tetapi ia membatasi jumlah keadaan awal.
Output dari fungsi-fungsi PRNG ini menghasilkan angka 32-bit positif (0 hingga 2 32 -1) yang kemudian dikonversi ke angka floating-point antara 0-1 (0 inklusif, 1 eksklusif) setara dengan
Math.random()
, jika Anda menginginkan angka acak untuk rentang tertentu, baca artikel ini di MDN . Jika Anda hanya menginginkan bit mentah, cukup hapus operasi pembagian akhir.Hal lain yang perlu diperhatikan adalah keterbatasan JS. Angka hanya dapat mewakili seluruh bilangan bulat hingga resolusi 53-bit. Dan ketika menggunakan operasi bitwise, ini dikurangi menjadi 32. Ini membuatnya sulit untuk mengimplementasikan algoritma yang ditulis dalam C atau C ++, yang menggunakan angka 64-bit. Porting kode 64-bit membutuhkan shims yang dapat secara drastis mengurangi kinerja. Jadi demi kesederhanaan dan efisiensi, saya hanya mempertimbangkan algoritma yang menggunakan matematika 32-bit, karena secara langsung kompatibel dengan JS.
sfc32 (Penghitung Cepat Sederhana)
sfc32 adalah bagian dari suite pengujian nomor acak PractRand (yang lolos tentu saja). sfc32 memiliki status 128-bit dan sangat cepat di JS.
Mulberry32
Mulberry32 adalah generator sederhana dengan keadaan 32-bit, tetapi sangat cepat dan memiliki kualitas yang baik (penulis menyatakan bahwa ia lulus semua pengujian suite pengujian gjrand dan memiliki periode 2 32 penuh , tetapi saya belum memverifikasi).
Saya akan merekomendasikan ini jika Anda hanya membutuhkan PRNG yang sederhana namun layak dan tidak perlu miliaran angka acak (lihat masalah Ulang Tahun ).
xoshiro128 **
Pada Mei 2018, xoshiro128 ** adalah anggota baru keluarga Xorshift , oleh Vigna / Blackman (yang juga menulis xoroshiro, yang digunakan di Chrome). Ini adalah generator tercepat yang menawarkan status 128-bit.
Para penulis mengklaim itu lulus tes keacakan dengan baik ( meskipun dengan peringatan ). Peneliti lain telah menunjukkan bahwa gagal beberapa tes di TestU01 (khususnya LinearComp dan BinaryRank). Dalam praktiknya, seharusnya tidak menyebabkan masalah ketika float digunakan (seperti implementasi ini), tetapi dapat menyebabkan masalah jika mengandalkan bit mentah yang rendah.
JSF (Jenkins Small Fast)
Ini adalah JSF atau 'smallprng' oleh Bob Jenkins (2007), pria yang membuat ISAAC dan SpookyHash . Itu melewati tes PractRand dan harus cukup cepat, meskipun tidak secepat SFC.
LCG (alias Lehmer / Park-Miller RNG atau MCG)
LCG sangat cepat dan sederhana, tetapi kualitas keacakannya sangat rendah, sehingga penggunaan yang tidak benar dapat menyebabkan bug di program Anda! Meskipun demikian, ini jauh lebih baik daripada beberapa jawaban yang menyarankan untuk menggunakan
Math.sin
atauMath.PI
! Ini adalah one-liner, yang bagus :).Implementasi ini disebut RNG standar minimal seperti yang diusulkan oleh Park – Miller pada tahun 1988 & 1993 dan diimplementasikan dalam C ++ 11 sebagai
minstd_rand
. Perlu diingat bahwa statusnya adalah 31-bit (31 bit memberi 2 miliar kemungkinan status, 32 bit memberikan dua kali lipat dari itu). Ini adalah tipe PRNG yang coba diganti oleh orang lain!Ini akan berhasil, tapi saya tidak akan menggunakannya kecuali Anda benar - benar membutuhkan kecepatan dan tidak peduli dengan kualitas keacakan (apa sih yang acak?). Sangat cocok untuk permainan yang macet atau demo atau sesuatu. LCG menderita korelasi benih, jadi yang terbaik adalah membuang hasil pertama LCG. Dan jika Anda bersikeras menggunakan LCG, menambahkan nilai kenaikan dapat meningkatkan hasil, tetapi mungkin latihan sia-sia ketika ada pilihan yang jauh lebih baik.
Tampaknya ada pengganda lain yang menawarkan keadaan 32-bit (peningkatan ruang-ruang):
Nilai LCG ini berasal dari: P. L'Ecuyer: Tabel Linear Congruential Generator dengan berbagai ukuran dan struktur kisi yang bagus, 30 April 1997.
sumber
seed = (seed * 185852 + 1) % 34359738337
.Math.imul
memungkinkan untuk meluap seperti saat menggunakan perkalian dalam C pada bilangan bulat 32-bit. Apa yang Anda sarankan adalah LCG yang memanfaatkan ruang integer JS lengkap, yang tentunya juga merupakan area yang menarik untuk dijelajahi. :)Tidak, tapi ini generator pseudorandom sederhana, sebuah implementasi Multiply-with-carry I yang diadaptasi dari Wikipedia (telah dihapus sejak):
EDIT: memperbaiki fungsi seed dengan membuatnya reset m_z
EDIT2: Kelemahan implementasi serius telah diperbaiki
sumber
seed
Fungsi tidak me-reset acak generator, karenamz_z
variabel berubah ketikarandom()
disebut. Oleh karena itu aturmz_z = 987654321
(atau nilai lain apa pun) diseed
m_w
, bukanm_z
. 2) Keduanyam_w
danm_z
diubah BERDASARKAN pada nilai sebelumnya, sehingga ia memodifikasi hasilnya.Algoritma Antti Sykäri bagus dan pendek. Saya awalnya membuat variasi yang menggantikan Math.random Javascript ketika Anda memanggil Math.seed, tetapi kemudian Jason berkomentar bahwa mengembalikan fungsi akan lebih baik:
Ini memberi Anda fungsionalitas lain yang tidak dimiliki Javascript: beberapa generator acak independen. Itu sangat penting jika Anda ingin memiliki beberapa simulasi berulang yang berjalan pada saat yang sama.
sumber
Math.random
yang memungkinkan Anda memiliki beberapa generator independen, bukan?Math.seed(42);
itu me-reset fungsi, jadi jika Andavar random = Math.seed(42); random(); random();
Anda mendapatkan0.70...
, kemudian0.38...
. Jika Anda mengatur ulang dengan meneleponvar random = Math.seed(42);
lagi, maka saat Anda menelepon lagirandom()
akan Anda dapatkan0.70...
lagi, dan kali berikutnya Anda akan mendapatkannya0.38...
lagi.random
alih-alih menimpa fungsi javascript asli. TimpaMath.random
dapat menyebabkan kompiler JIST untuk mengoptimalkan semua kode Anda.Silakan lihat karya Pierre L'Ecuyer kembali ke akhir 1980-an dan awal 1990-an. Ada juga yang lain. Membuat generator bilangan acak (semu) sendiri, jika Anda bukan ahli, cukup berbahaya, karena ada kemungkinan besar hasilnya tidak acak secara statistik atau memiliki periode kecil. Pierre (dan lainnya) telah mengumpulkan beberapa generator angka acak yang baik (pseudo) yang mudah diimplementasikan. Saya menggunakan salah satu generator LFSR-nya.
https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf
Phil Troy
sumber
Menggabungkan beberapa jawaban sebelumnya, ini adalah fungsi acak unggulan yang Anda cari:
sumber
Math.seed(0)()
mengembalikan0.2322845458984375
, danMath.seed(1)()
mengembalikan0.23228873685002327
. Mengubah keduanyam_w
danm_z
menurut benih tampaknya membantu.var m_w = 987654321 + s; var m_z = 123456789 - s;
menghasilkan distribusi nilai pertama yang bagus dengan benih yang berbeda.Untuk menulis generator acak semu sendiri cukup sederhana.
Saran dari Dave Scotese berguna tetapi, seperti yang ditunjukkan oleh orang lain, tidak terdistribusi secara merata.
Namun, itu bukan karena argumen bilangan bulat tentang dosa. Itu hanya karena rentang dosa, yang kebetulan merupakan proyeksi satu dimensi dari sebuah lingkaran. Jika Anda mengambil sudut lingkaran, itu akan menjadi seragam.
Jadi alih-alih dosa (x) gunakan arg (exp (i * x)) / (2 * PI).
Jika Anda tidak menyukai urutan linier, campur sedikit dengan xor. Faktor sebenarnya tidak terlalu penting.
Untuk menghasilkan n angka acak semu, seseorang dapat menggunakan kode:
Harap perhatikan juga bahwa Anda tidak dapat menggunakan urutan acak semu ketika entropi nyata diperlukan.
sumber
Banyak orang yang membutuhkan generator nomor acak yang dapat di seedable dalam Javascript hari ini menggunakan modul seedrandom David Bau .
sumber
Math.random
tidak, tetapi perpustakaan ran memecahkan ini. Ini memiliki hampir semua distribusi yang dapat Anda bayangkan dan mendukung generasi nomor acak unggulan. Contoh:sumber
Saya telah menulis fungsi yang mengembalikan nomor acak yang diunggulkan, menggunakan Math.sin untuk memiliki nomor acak yang panjang dan menggunakan benih untuk memilih angka dari itu.
Gunakan:
itu akan mengembalikan nomor yang Anda seeded parameter pertama adalah nilai string apa pun; benihmu. parameter kedua adalah berapa banyak digit yang akan kembali.
sumber
Pendekatan sederhana untuk seed tetap:
sumber
Untuk angka antara 0 dan 100.
sumber
Math.random
sedemikian rupa sehingga setiap kaliMath.random
disemai dengan benih yang sama, itu akan menghasilkan serangkaian nomor acak yang sama berturut-turut. Pertanyaan ini bukan, katakanlah, tentang penggunaan / demonstrasi aktual dariMath.random
.