Fungsi JavaScript Math.random()
mengembalikan nilai acak antara 0 dan 1, secara otomatis diunggulkan berdasarkan waktu saat ini (mirip dengan Java, saya percaya). Namun, saya tidak berpikir ada cara untuk mengatur benih Anda sendiri untuk itu.
Bagaimana saya bisa membuat generator angka acak yang dapat saya berikan nilai benih saya sendiri, sehingga saya bisa membuatnya menghasilkan urutan nomor acak (pseudo) berulang?
javascript
random
seed
scunliffe
sumber
sumber
Jawaban:
Salah satu pilihan adalah http://davidbau.com/seedrandom yang merupakan pengganti drop-in Math.random () yang dapat disemai dengan RC4 dengan properti yang bagus.
sumber
Jika Anda tidak memerlukan kemampuan penyemaian, gunakan saja
Math.random()
dan bangun fungsi pembantu di sekitarnya (mis.randRange(start, end)
).Saya tidak yakin apa RNG yang Anda gunakan, tetapi yang terbaik adalah mengetahui dan mendokumentasikannya sehingga Anda mengetahui karakteristik dan keterbatasannya.
Seperti kata Starkii, Mersenne Twister adalah PRNG yang baik, tetapi tidak mudah untuk diterapkan. Jika Anda ingin melakukannya sendiri, cobalah menerapkan LCG - sangat mudah, memiliki kualitas keacakan yang layak (tidak sebagus Mersenne Twister), dan Anda dapat menggunakan beberapa konstanta populer.
EDIT: pertimbangkan opsi hebat pada jawaban ini untuk implementasi RNG yang dapat diunggulkan pendek, termasuk opsi LCG.
sumber
this.a * this.state
kemungkinan menghasilkan angka lebih besar dari 2 ^ 53. Hasilnya adalah rentang keluaran terbatas, dan untuk beberapa benih mungkin periode yang sangat singkat. Lebih lanjut secara umum menggunakan kekuatan dua untukm
menghasilkan beberapa pola yang cukup jelas, ketika Anda mengeluarkan operasi modulus daripada pemotongan sederhana pula, tidak ada alasan untuk tidak menggunakan prime.Jika Anda ingin dapat menentukan seed, Anda hanya perlu mengganti panggilan ke
getSeconds()
dangetMinutes()
. Anda bisa memasukkan int dan menggunakan setengahnya mod 60 untuk nilai detik dan setengah modulo 60 lainnya untuk memberi Anda bagian lainnya.Yang sedang berkata, metode ini terlihat seperti sampah. Melakukan pembangkitan angka acak yang tepat sangat sulit. Masalah yang jelas dengan ini adalah bahwa seed number acak didasarkan pada detik dan menit. Untuk menebak seed dan membuat ulang aliran angka acak Anda hanya perlu mencoba 3600 kombinasi detik dan menit yang berbeda. Ini juga berarti bahwa hanya ada 3600 kemungkinan benih yang berbeda. Ini bisa diperbaiki, tapi saya akan curiga dengan RNG ini sejak awal.
Jika Anda ingin menggunakan RNG yang lebih baik, coba Twister Mersenne . Ini adalah RNG yang teruji dengan baik dan cukup kuat dengan orbit yang sangat besar dan kinerja yang sangat baik.
EDIT: Saya benar-benar harus benar dan merujuk ini sebagai Pseudo Random Number Generator atau PRNG.
sumber
Saya menggunakan port JavaScript dari Mersenne Twister: https://gist.github.com/300494 Ini memungkinkan Anda untuk mengatur seed secara manual. Juga, sebagaimana disebutkan dalam jawaban lain, Mersenne Twister adalah PRNG yang sangat bagus.
sumber
Kode yang Anda daftarkan terlihat seperti Lehmer RNG . Jika demikian,
2147483647
bilangan bulat bertanda 32-bit terbesar,2147483647
adalah bilangan prima 32-bit terbesar, dan48271
merupakan pengali periode penuh yang digunakan untuk menghasilkan angka.Jika ini benar, Anda bisa memodifikasi
RandomNumberGenerator
untuk mengambil parameter tambahanseed
, dan kemudian mengaturthis.seed
keseed
; tetapi Anda harus berhati-hati untuk memastikan benih akan menghasilkan distribusi angka acak yang baik (Lehmer bisa aneh seperti itu) - tetapi sebagian besar benih akan baik-baik saja.sumber
Berikut ini adalah PRNG yang dapat diberi umpan benih khusus. Memanggil
SeedRandom
akan mengembalikan fungsi generator acak.SeedRandom
dapat dipanggil tanpa argumen untuk menabur kembali fungsi acak yang dikembalikan dengan waktu saat ini, atau dapat disebut dengan 1 atau 2 non-negatif inters sebagai argumen untuk menaburnya dengan bilangan bulat tersebut. Karena akurasi titik float penyemaian dengan hanya 1 nilai hanya akan memungkinkan generator untuk diinisiasi ke salah satu dari 2 ^ 53 negara yang berbeda.Fungsi generator acak yang dikembalikan mengambil 1 argumen integer bernama
limit
, batasnya harus dalam kisaran 1 hingga 4294965886, fungsi akan mengembalikan angka dalam kisaran 0 hingga batas-1.Contoh penggunaan:
Generator ini menunjukkan sifat-sifat berikut:
mod
nilai menjadi bilangan prima tidak ada pola sederhana dalam output, tidak peduli batas yang dipilih. Ini tidak seperti beberapa PRNG sederhana yang menunjukkan beberapa pola yang cukup sistematis.sumber
for (var i = 0; i < 400; i++) { console.log("input: (" + i * 245 + ", " + i * 553 + ") | output: " + SeedRandom(i * 245, i * 553)(20)); }
Jika Anda memprogram dalam Typcript, saya mengadaptasi implementasi Mersenne Twister yang membawa jawaban Christoph Henkelmann ke utas ini sebagai kelas naskah:
Anda dapat menggunakannya sebagai berikut:
periksa sumber untuk lebih banyak metode.
sumber
Saya menemukan kode ini menendang sekitar dan tampaknya berfungsi dengan baik untuk mendapatkan nomor acak dan kemudian menggunakan seed sesudahnya tetapi saya tidak yakin bagaimana logika bekerja (misalnya dari mana nomor 2345678901, 48271 & 2147483647 berasal).
sumber
RandomNumberGenerator
dannextRandomNumber
fungsinya sebenarnya sudah ada sejak tahun 1996. Seharusnya itu adalah Lehmer / LCG RNG. Ini menggunakan beberapa matematika pintar untuk melakukan modulo aritmatika pada bilangan bulat 32 bit yang seharusnya terlalu kecil untuk mengandung beberapa nilai menengah. Masalahnya, JavaScript tidak mengimplementasikan bilangan bulat 32 bit, melainkan mengapung 64 bit, dan karena pembagiannya bukan pembagian bilangan bulat seperti kode ini menganggap hasilnya bukan generator Lehmer. Memang menghasilkan beberapa hasil yang tampak acak, tetapi jaminan generator Lehmer tidak berlaku.createRandomNumber
fungsi tambahan kemudian, itu tidak cukup banyak segala sesuatu yang salah, terutama itu instantiates RNG baru setiap kali hal itu disebut, yang berarti bahwa panggilan dalam suksesi cepat semua akan menggunakan pelampung yang sama. Dalam kode yang diberikan hampir tidak mungkin untuk'a'
dipasangkan dengan apa pun kecuali'1'
dan'red'
.OK, inilah solusi yang saya pilih.
Pertama, Anda membuat nilai seed menggunakan fungsi "newseed ()". Lalu Anda meneruskan nilai seed ke fungsi "srandom ()". Terakhir, fungsi "srandom ()" mengembalikan nilai acak semu antara 0 dan 1.
Bit penting adalah bahwa nilai seed disimpan di dalam array. Jika itu hanya bilangan bulat atau float, nilai akan ditimpa setiap kali fungsi dipanggil, karena nilai integer, float, string dan sebagainya disimpan langsung di stack dibandingkan hanya pointer seperti dalam kasus array dan benda lainnya. Dengan demikian, mungkin nilai benih tetap persisten.
Akhirnya, dimungkinkan untuk mendefinisikan fungsi "srandom ()" sehingga merupakan metode dari objek "Math", tetapi saya akan menyerahkannya kepada Anda untuk mencari tahu. ;)
Semoga berhasil!
JavaScript:
Lua 4 (lingkungan target pribadi saya):
sumber
seedobj[0] * seedobja
kemungkinan menghasilkan angka lebih besar dari 2 ^ 53. Hasilnya adalah rentang keluaran terbatas, dan untuk beberapa benih mungkin periode yang sangat singkat.