Random'da (Java 7) 181783497276652981 ve 8682522807148012 ile ne var?


112

Neden seçildi 181783497276652981ve 8682522807148012seçildi Random.java?

Java SE JDK 1.7'den ilgili kaynak kodu şöyledir:

/**
 * 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);

Bu nedenle, new Random()herhangi bir tohum parametresi olmadan çağırmak , geçerli "çekirdek benzersizleştiriciyi" alır ve onunla birlikte XOR'tur System.nanoTime(). Daha sonra 181783497276652981çağrıldığında saklanmak üzere başka bir tohum benzersizleştiricisi oluşturmak için kullanır new Random().

Değişmezleri 181783497276652981Lve 8682522807148012Lsabitler yerleştirilir değildir, ancak bunlar başka bir yerde görünmez.

İlk başta yorum bana kolay bir ipucu veriyor. Bu makale için çevrimiçi arama yapmak asıl makaleyi verir . 8682522807148012Kağıt görünmüyorsa, ama 181783497276652981görünmüyor - başka bir numaraya, bir alt dize olarak 1181783497276652981ise, 181783497276652981bir ile 1de başa.

Makale 1181783497276652981, doğrusal bir eşleşik üretici için iyi bir "değer" sağlayan bir sayı olduğunu iddia ediyor . Bu numara Java'ya yanlış mı kopyalandı? Kabul 181783497276652981edilebilir bir değeri var mı?

Ve neden 8682522807148012seçildi?

Herhangi bir sayı için çevrimiçi arama yapmak herhangi bir açıklama getirmez, sadece bu sayfanın1 önüne düştüğünü de fark eder 181783497276652981.

Bu iki sayı kadar işe yarayacak başka numaralar seçilebilir miydi? Neden ya da neden olmasın?


Çarpma kesinlikle bir taşma ile sonuçlanacak olsa da, bahsedilen sabitlerin hiçbirinin (en başında olanlar bile) sığamayacak kadar büyük olmadığını belirtmek isterim.
nanofarad

6
86825228071480122010'da yapılan revizyonlarda görülebileceği gibi, sınıfın önceki sürümünün mirasıdır . 181783497276652981LGerçekten de bir yazım hatası gibi görünüyor ve bir hata raporu olabilir.
assylias

6
Ya bir yazım hatası, yani bir hata ya da açıklanmayan motivasyonu olan bir özellik. Yazarlara sormanız gerekir. Burada aldığınız her şey, az çok bilgisiz bir fikir olacaktır. Bunun bir hata olduğunu düşünüyorsanız, bir hata raporu gönderin.
Marquis of Lorne

1
Özellikle farklı cevaplar verildiğinde, bu her sabit için iki ayrı soru olabilir.
Mark Hurd

1
Böylesine temel bir sınıfa yerleştirilmiş küresel bir ölçeklenebilirlik darboğazı görmek üzücü. seedUniquifier64 çekirdekli bir kutuda aşırı derecede tartışılabilir. İş parçacığı yerel daha ölçeklenebilir olurdu.
usr

Yanıtlar:


57
  1. Bu numara Java'ya yanlış mı kopyalandı?

    Evet, bir yazım hatası gibi görünüyor.

  2. 181783497276652981'in kabul edilebilir bir değeri var mı?

    Bu, makalede sunulan değerlendirme algoritması kullanılarak belirlenebilir. Ancak "orijinal" sayının değeri muhtemelen daha yüksektir.

  3. Ve neden 8682522807148012 seçildi?

    Rastgele görünüyor. Kod yazılırken System.nanoTime () sonucu olabilir.

  4. Bu iki sayı kadar işe yarayacak başka numaralar seçilebilir miydi?

    Her sayı eşit derecede "iyi" olmaz. Yani hayır.

Tohumlama Stratejileri

JRE'nin farklı sürümleri ve uygulaması arasında varsayılan tohumlama şemasında farklılıklar vardır.

public Random() { this(System.currentTimeMillis()); }
public Random() { this(++seedUniquifier + System.nanoTime()); }
public Random() { this(seedUniquifier() ^ System.nanoTime()); }

Bir satırda birden fazla RNG oluşturursanız ilki kabul edilemez. Oluşturma süreleri aynı milisaniye aralığına düşerse, tamamen aynı dizileri verecektir. (aynı tohum => aynı sıra)

İkincisi, iş parçacığı için güvenli değildir. Birden çok iş parçacığı, aynı anda başlatılırken aynı RNG'leri alabilir. Ek olarak, sonraki başlatmaların tohumları ilişkilendirilme eğilimindedir. Sistemin gerçek zamanlayıcı çözünürlüğüne bağlı olarak, tohum dizisi doğrusal olarak artabilir (n, n + 1, n + 2, ...). Belirtildiği gibi rastgele tohumlar olması gerekiyor nasıl farklı? ve referans verilen makale Sahte rasgele sayı üreteçlerinin başlatılmasındaki yaygın kusurlar , ilişkili tohumlar çoklu RNG'lerin gerçek dizileri arasında korelasyon oluşturabilir.

Üçüncü yaklaşım, iş parçacıkları ve sonraki başlatmalar arasında bile rastgele dağıtılmış ve dolayısıyla ilişkisiz tohumlar oluşturur. Dolayısıyla mevcut java dokümanları:

Bu yapıcı, rasgele sayı üretecinin tohumunu, bu kurucunun herhangi bir başka çağrısından çok büyük olasılıkla farklı bir değere ayarlar.

"iş parçacıkları arasında" ve "ilişkisiz" olarak genişletilebilir

Tohum Sırası Kalitesi

Ancak, tohumlama dizisinin rastgeleliği yalnızca temeldeki RNG kadar iyidir. Bu java uygulamasında çekirdek dizisi için kullanılan RNG, c = 0 ve m = 2 ^ 64 olan bir çarpımsal doğrusal eşleşik oluşturucu (MLCG) kullanır. (2 ^ 64 modülü örtük olarak 64 bit uzunluğundaki tam sayıların taşmasıyla verilir) Sıfır c ve 2 modülünün gücü nedeniyle, "kalite" (döngü uzunluğu, bit korelasyonu, ...) sınırlıdır . Kağıdın dediği gibi, toplam döngü uzunluğunun yanı sıra, her bir bitin, daha az önemli bitler için katlanarak azalan kendi döngü uzunluğu vardır. Bu nedenle, daha düşük bitler daha küçük bir tekrar modeline sahiptir. (SeedUniquifier () sonucunun, gerçek RNG'de 48 bitlik kesilmeden önce bit tersine çevrilmesi gerekir)

Ama hızlı! Gereksiz karşılaştırma ve ayarlama döngülerini önlemek için döngü gövdesi hızlı olmalıdır. Bu muhtemelen bu belirli MLCG'nin toplamasız, xoringsiz, sadece bir çarpma işleminin kullanımını açıklıyor.

Bahsedilen makale c = 0 ve m = 2 ^ 64 için 1181783497276652981 olarak iyi "çarpanların" bir listesini sunmaktadır.

Sonuç olarak: A çaba için @ JRE geliştiricileri;) Ama bir yazım hatası var. (Ama kim bilir, birisi değerlendirmedikçe, eksik lider 1'in aslında tohumlama RNG'sini iyileştirme olasılığı vardır.)

Ancak bazı çarpanlar kesinlikle daha kötüdür: "1" sabit bir diziye yol açar. "2" tek bitlik bir hareket dizisine yol açar (bir şekilde ilişkili) ...

RNG'ler için sekanslar arası korelasyon aslında birden fazla rastgele sekansın somutlaştırıldığı ve hatta paralelleştirildiği (Monte Carlo) Simülasyonları ile ilgilidir. Bu nedenle, "bağımsız" simülasyon çalıştırmaları elde etmek için iyi bir tohumlama stratejisi gereklidir. Bu nedenle C ++ 11 standardı, ilişkisiz tohumlar üretmek için bir Tohum Dizisi kavramını ortaya koymaktadır .


3
En azından hala tuhaftır, eğer en önemli olanı yerine en önemsiz olanı düşürmüşlerse, o zaman her çarpma, sonunda (62 adımdan sonra) seedUniquifiersıfıra takılana kadar biraz kaybeder .
harold

9

Rastgele sayı oluşturucu için kullanılan denklemin:

LCGEquation

X (n + 1) bir sonraki sayı, a çarpan, X (n) mevcut sayı, c artış ve m modüldür.

Daha ayrıntılı olarak bakarsanız Random, a, c ve m sınıfın başlığında tanımlanır

private static final long multiplier = 0x5DEECE66DL;   //= 25214903917 -- 'a'
private static final long addend = 0xBL;               //= 11          -- 'c'
private static final long mask = (1L << 48) - 1;       //= 2 ^ 48 - 1  -- 'm'

ve yönteme baktığımızda protected int next(int bits)bu denklemin uygulandığı

nextseed = (oldseed * multiplier + addend) & mask;
//X(n+1) =  (X(n)   *      a     +    c  ) mod m

Bu, yöntemin seedUniquifier()gerçekte X (n) elde ettiğini veya ilk durumda X (0) başlatılmasında aslında 8682522807148012 * 181783497276652981bu değerin daha sonra değeriyle değiştirildiğini gösterir System.nanoTime(). Bu algoritma, yukarıdaki denklemle tutarlıdır, ancak aşağıdaki X (0) = 8682522807148012, a = 181783497276652981, m = 2 ^ 64 ve c = 0 ile tutarlıdır. Ancak, mod m, uzun taşma tarafından önceden oluşturulduğundan, yukarıdaki denklem

EQ2'ye

Kağıda bakıldığında, a = değeri 1181783497276652981m = 2 ^ 64, c = 0'dır. Dolayısıyla, sadece bir yazım hatası ve 8682522807148012eski koddan rastgele seçilmiş bir sayı gibi görünen X (0) değeri gibi görünüyor. için Random. Burada görüldüğü gibi. Ancak bu seçilmiş sayıların değeri hala geçerli olabilir, ancak Thomas B.'nin bahsettiği gibi, muhtemelen makaledeki kadar "iyi" değil.

DÜZENLEME - Orijinal düşüncelerin altında o zamandan beri açıklığa kavuşturulmuştur, bu nedenle göz ardı edilebilir ancak referans için bırakılabilir

Bu bana şu sonuçlara götürüyor:

  1. Kağıda referans, değerin kendisi için değil, a, c ve m'nin farklı değerleri nedeniyle değerleri elde etmek için kullanılan yöntemler içindir.

  2. Değerin aksi takdirde baştaki 1'den farklı olması ve yorumun yanlış yerleştirilmesi (yine de buna inanmak için mücadele ediyor) sadece tesadüftür.

VEYA

Makaledeki tablolarda ciddi bir yanlış anlaşılma olmuştur ve geliştiriciler, özellikle tablo değerini ilk etapta kullanmanın amacının ne olduğu çarpıldığında, rastgele bir değer seçmişlerdir, özellikle herhangi bir şekilde kendi tohum değeri, bu durumda bu değerler dikkate alınmaz bile

Yani sorunuzu cevaplamak için

Bu iki sayı kadar işe yarayacak başka numaralar seçilebilir miydi? Neden ya da neden olmasın?

Evet, herhangi bir sayı kullanılabilirdi, aslında Rastgele Örnekleme yaparken bir çekirdek değeri belirtirseniz başka bir değer kullanıyorsunuzdur. Bu değerin jeneratörün performansı üzerinde herhangi bir etkisi yoktur, bu sınıf içerisinde sabit kodlanmış a, c ve m değerleri ile belirlenir.


1
Gerçekte değil - İki algoritma vardır: (i) 1 kurucu her çağrıldığında yeni bir rastgele çekirdek oluşturmak için. Bu algo basit bir X_n + 1 = X_n * a kullanır. Uzun taşma nedeniyle bu, X_n + 1 = X_n * a mod m'ye eşdeğerdir. A = 181783497276652981 ve m = 2 ^ 64 ile. (ii) Belirli bir tohumdan başlayarak bir dizi rastgele sayı üreten başka bir algo. Bu ikinci algo, bahsettiğiniz algo ve dokümanlar, " Bu, Knuth'un Bilgisayar Programlama Sanatı'nda tanımladığı gibi, doğrusal bir uyumlu sözde rasgele sayı üreteci " olduğunu açıklıyor .
assylias

1
@assylias Söylediğinizi görüyorum, kaynak koduna o kadar kapıldım Randomve alıntı yapılan kağıt, orijinal soruyu tamamen aştım, yakında düzenleyeceğim, teşekkürler.
Java Devil

3

Sağladığınız bağlantıya göre , 2 ^ 64'ten en iyi verimi ( eksik 1'i ekledikten sonra ) seçtiler çünkü uzun 2 ^ 128'den bir sayı olamaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.