Mengapa 181783497276652981
dan 8682522807148012
dipilih Random.java
?
Berikut kode sumber yang relevan dari Java SE JDK 1.7:
/**
* Creates a new random number generator. This constructor sets
* the seed of the random number generator to a value very likely
* to be distinct from any other invocation of this constructor.
*/
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
Jadi, memanggil new Random()
tanpa parameter seed apapun membutuhkan "seed uniquifier" saat ini dan melakukan XOR dengannya System.nanoTime()
. Kemudian menggunakan 181783497276652981
untuk membuat pengunikan benih lain untuk disimpan untuk panggilan berikutnya new Random()
.
Literal 181783497276652981L
dan 8682522807148012L
tidak ditempatkan dalam konstanta, tetapi tidak muncul di tempat lain.
Awalnya komentar itu memberi saya petunjuk mudah. Pencarian online untuk artikel itu menghasilkan artikel yang sebenarnya . 8682522807148012
tidak muncul di koran, tapi 181783497276652981
tidak muncul - sebagai substring dari nomor lain, 1181783497276652981
yang 181783497276652981
dengan 1
ditambahkan.
Makalah ini mengklaim bahwa itu 1181783497276652981
adalah angka yang menghasilkan "jasa" yang baik untuk generator kongruensial linier. Apakah nomor ini salah disalin ke dalam Java? Apakah 181783497276652981
memiliki pahala yang dapat diterima?
Dan mengapa 8682522807148012
dipilih?
Pencarian online untuk salah satu nomor tidak menghasilkan penjelasan, hanya halaman ini yang juga mengetahui penurunan 1
di depan 181783497276652981
.
Mungkinkah nomor lain telah dipilih yang berfungsi sebaik kedua nomor ini? Mengapa atau mengapa tidak?
8682522807148012
merupakan warisan dari versi kelas sebelumnya, seperti yang dapat dilihat pada revisi yang dibuat pada tahun 2010 . The181783497276652981L
tampaknya menjadi salah ketik memang dan Anda bisa mengajukan laporan bug.seedUniquifier
dapat sangat dipertandingkan pada kotak 64 inti. Thread-local akan lebih terukur.Jawaban:
Ya, sepertinya salah ketik.
Ini dapat ditentukan dengan menggunakan algoritma evaluasi yang disajikan dalam makalah. Tetapi manfaat dari angka "asli" mungkin lebih tinggi.
Sepertinya acak. Ini bisa jadi hasil dari System.nanoTime () saat kode ditulis.
Tidak setiap angka akan sama-sama "baik". Jadi tidak.
Strategi Pembibitan
Ada perbedaan dalam skema penyemaian default antara versi yang berbeda dan implementasi JRE.
Yang pertama tidak dapat diterima jika Anda membuat beberapa RNG secara berurutan. Jika waktu pembuatannya berada dalam kisaran milidetik yang sama, mereka akan memberikan urutan yang sepenuhnya identik. (benih yang sama => urutan yang sama)
Yang kedua tidak aman untuk benang. Beberapa utas bisa mendapatkan RNG identik saat menginisialisasi pada saat yang bersamaan. Selain itu, benih inisialisasi berikutnya cenderung berkorelasi. Bergantung pada resolusi pengatur waktu aktual dari sistem, urutan benih dapat meningkat secara linier (n, n + 1, n + 2, ...). Seperti yang dinyatakan dalam Seberapa berbedanya benih acak? dan kertas referensi Cacat umum dalam inisialisasi pembuat nomor pseudorandom , benih berkorelasi dapat menghasilkan korelasi di antara urutan sebenarnya dari beberapa RNG.
Pendekatan ketiga menciptakan benih yang didistribusikan secara acak dan dengan demikian tidak berkorelasi, bahkan di seluruh utas dan inisialisasi berikutnya. Jadi dokumen java saat ini:
dapat diperpanjang dengan "melintasi utas" dan "tidak berkorelasi"
Kualitas Urutan Benih
Tetapi urutan penyemaian yang acak hanya sebaik RNG yang mendasarinya. RNG yang digunakan untuk urutan seed pada implementasi java ini menggunakan multiplicative linear congruential generator (MLCG) dengan c = 0 dan m = 2 ^ 64. (Modulus 2 ^ 64 secara implisit diberikan oleh luapan bilangan bulat panjang 64bit) Karena nol c dan modulus pangkat-2, "kualitas" (panjang siklus, korelasi bit, ...) terbatas . Seperti yang dikatakan makalah, selain panjang siklus keseluruhan, setiap bit memiliki panjang siklus sendiri, yang menurun secara eksponensial untuk bit yang kurang signifikan. Jadi, bit yang lebih rendah memiliki pola pengulangan yang lebih kecil. (Hasil seedUniquifier () harus dibalik bit, sebelum dipotong menjadi 48-bit di RNG aktual)
Tapi itu cepat! Dan untuk menghindari perbandingan-dan-set-loop yang tidak perlu, badan loop harus cepat. Ini mungkin menjelaskan penggunaan MLCG khusus ini, tanpa penambahan, tanpa xoring, hanya satu perkalian.
Dan makalah tersebut menyajikan daftar "pengali" yang baik untuk c = 0 dan m = 2 ^ 64, sebagai 1181783497276652981.
Semua dalam semua: A untuk usaha @ JRE-developer;) Tapi ada kesalahan ketik. (Tapi siapa tahu, kecuali seseorang mengevaluasinya, ada kemungkinan bahwa petunjuk 1 yang hilang benar-benar meningkatkan RNG penyemaian.)
Tetapi beberapa pengganda pasti lebih buruk: "1" mengarah ke urutan yang konstan. "2" mengarah ke urutan pemindahan bit tunggal (entah bagaimana berkorelasi) ...
Korelasi antar-urutan untuk RNG sebenarnya relevan untuk Simulasi (Monte Carlo), di mana beberapa urutan acak dipakai dan bahkan diparalelkan. Oleh karena itu, strategi penyemaian yang baik diperlukan untuk menjalankan simulasi "independen". Oleh karena itu, standar C ++ 11 memperkenalkan konsep Urutan Benih untuk menghasilkan benih yang tidak berkorelasi.
sumber
seedUniquifier
menjadi macet di nol.Jika Anda menganggap bahwa persamaan yang digunakan untuk generator bilangan acak adalah:
Di mana X (n + 1) adalah bilangan berikutnya, a adalah pengali, X (n) adalah bilangan saat ini, c adalah kenaikan dan m adalah modulus.
Jika Anda melihat lebih jauh
Random
, a, c dan m didefinisikan di header kelasdan melihat metode
protected int next(int bits)
ini adalah persamaan diimplementasikanIni menyiratkan bahwa metode
seedUniquifier()
tersebut sebenarnya mendapatkan X (n) atau dalam kasus pertama pada inisialisasi X (0) yang sebenarnya8682522807148012 * 181783497276652981
, nilai ini kemudian dimodifikasi lebih lanjut dengan nilaiSystem.nanoTime()
. Algoritma ini konsisten dengan persamaan di atas tetapi dengan X berikut (0) =8682522807148012
, a =181783497276652981
, m = 2 ^ 64 dan c = 0. Tetapi karena mod m dari dibentuk sebelumnya oleh long overflow persamaan di atas hanya menjadiMelihat kertas tersebut , nilai a =
1181783497276652981
untuk m = 2 ^ 64, c = 0. Jadi tampaknya hanya salah ketik dan nilai8682522807148012
untuk X (0) yang tampaknya merupakan nomor yang dipilih secara acak dari kode lama untukRandom
. Seperti yang terlihat di sini. Namun kelebihan dari nomor yang dipilih ini masih bisa valid tetapi seperti yang disebutkan oleh Thomas B. mungkin tidak “sebaik” yang ada di koran.EDIT - Di bawah pemikiran asli sejak itu telah diklarifikasi sehingga dapat diabaikan tetapi meninggalkannya untuk referensi
Ini membawa saya pada kesimpulan:
Referensi kertas bukan untuk nilai itu sendiri tetapi untuk metode yang digunakan untuk mendapatkan nilai karena perbedaan nilai a, c dan m
Hanya kebetulan bahwa nilainya sama selain dari 1 di awal dan komentar salah tempat (meskipun masih berjuang untuk mempercayainya)
ATAU
Ada kesalahpahaman yang serius tentang tabel di makalah dan para pengembang baru saja memilih nilai secara acak karena pada saat dikalikan apa gunanya menggunakan nilai tabel di tempat pertama terutama karena Anda bisa memberikan memiliki nilai benih dengan cara apapun dalam hal ini nilai-nilai ini bahkan tidak diperhitungkan
Jadi, untuk menjawab pertanyaanmu
Ya, nomor apa pun dapat digunakan, bahkan jika Anda menentukan nilai benih saat Anda Membuat Instansiasi Acak, Anda menggunakan nilai lain. Nilai ini tidak berpengaruh pada kinerja generator, hal ini ditentukan oleh nilai a, c dan m yang di-hardcode di dalam kelas.
sumber
Random
dan makalah yang dikutip saya benar-benar melampaui pertanyaan asli, akan segera mengedit, terima kasih.Sesuai tautan yang Anda berikan, mereka telah memilih ( setelah menambahkan 1 :) yang hilang ) hasil terbaik dari 2 ^ 64 karena lama tidak dapat memiliki angka dari 2 ^ 128
sumber