Warum wurden 181783497276652981
und 8682522807148012
ausgewählt Random.java
?
Hier ist der relevante Quellcode aus 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);
new Random()
Wenn Sie also ohne einen Seed-Parameter aufrufen, wird der aktuelle "Seed Uniquifier" verwendet und mit XORs versehen System.nanoTime()
. Anschließend wird 181783497276652981
ein weiterer Seed-Uniquifier erstellt, der beim nächsten Aufruf gespeichert werden new Random()
soll.
Die Literale 181783497276652981L
und 8682522807148012L
werden nicht in Konstanten platziert, aber sie erscheinen nirgendwo anders.
Der Kommentar gibt mir zunächst einen einfachen Hinweis. Wenn Sie online nach diesem Artikel suchen, erhalten Sie den tatsächlichen Artikel . 8682522807148012
erscheint nicht im Papier, sondern 181783497276652981
erscheint - als Teilzeichenfolge einer anderen Zahl 1181783497276652981
, die 181783497276652981
mit einem 1
vorangestellten Zeichen versehen ist.
Das Papier behauptet, dass dies 1181783497276652981
eine Zahl ist, die einen guten "Verdienst" für einen linearen Kongruenzgenerator ergibt. Wurde diese Nummer einfach falsch in Java kopiert? Hat 181783497276652981
ein akzeptables Verdienst?
Und warum wurde 8682522807148012
gewählt?
Die Online-Suche nach einer der beiden Nummern liefert keine Erklärung, nur diese Seite , auf der auch das vorangestellte Feld 1
angezeigt wird 181783497276652981
.
Könnten andere Nummern gewählt worden sein, die genauso gut funktioniert hätten wie diese beiden Nummern? Warum oder warum nicht?
8682522807148012
ist ein Erbe der vorherigen Version der Klasse, wie aus den 2010 vorgenommenen Überarbeitungen hervorgeht . Das181783497276652981L
scheint in der Tat ein Tippfehler zu sein und Sie könnten einen Fehlerbericht einreichen.seedUniquifier
kann auf einer 64-Core-Box extrem umstritten sein. Ein Thread-Local wäre skalierbarer gewesen.Antworten:
Ja, scheint ein Tippfehler zu sein.
Dies könnte unter Verwendung des in der Arbeit vorgestellten Bewertungsalgorithmus bestimmt werden. Aber der Wert der "ursprünglichen" Zahl ist wahrscheinlich höher.
Scheint zufällig zu sein. Dies könnte das Ergebnis von System.nanoTime () sein, als der Code geschrieben wurde.
Nicht jede Zahl wäre gleich "gut". Also nein.
Seeding-Strategien
Es gibt Unterschiede im Standard-Seeding-Schema zwischen verschiedenen Versionen und der Implementierung der JRE.
Der erste ist nicht akzeptabel, wenn Sie mehrere RNGs hintereinander erstellen. Wenn ihre Erstellungszeiten im gleichen Millisekundenbereich liegen, ergeben sie völlig identische Sequenzen. (gleicher Samen => gleiche Sequenz)
Der zweite ist nicht threadsicher. Mehrere Threads können bei gleichzeitiger Initialisierung identische RNGs erhalten. Zusätzlich neigen Samen nachfolgender Initialisierungen dazu, korreliert zu sein. Abhängig von der tatsächlichen Timer-Auflösung des Systems kann die Startsequenz linear ansteigen (n, n + 1, n + 2, ...). Wie in Wie unterschiedlich müssen zufällige Samen sein? und das referenzierte Papier Häufige Fehler bei der Initialisierung von Pseudozufallszahlengeneratoren , korrelierte Seeds können eine Korrelation zwischen den tatsächlichen Sequenzen mehrerer RNGs erzeugen.
Der dritte Ansatz erzeugt zufällig verteilte und damit nicht korrelierte Seeds, selbst über Threads und nachfolgende Initialisierungen hinweg. Also die aktuellen Java-Dokumente:
könnte durch "über Threads" und "unkorreliert" erweitert werden
Samensequenzqualität
Die Zufälligkeit der Seeding-Sequenz ist jedoch nur so gut wie das zugrunde liegende RNG. Das in dieser Java-Implementierung für die Seed-Sequenz verwendete RNG verwendet einen multiplikativen linearen Kongruenzgenerator (MLCG) mit c = 0 und m = 2 ^ 64. (Der Modul 2 ^ 64 ist implizit durch den Überlauf von 64 Bit langen ganzen Zahlen gegeben.) Aufgrund der Null c und der Potenz des 2-Moduls ist die "Qualität" (Zykluslänge, Bitkorrelation, ...) begrenzt . Wie das Papier sagt, hat neben der Gesamtzykluslänge jedes einzelne Bit eine eigene Zykluslänge, die für weniger signifikante Bits exponentiell abnimmt. Somit haben niedrigere Bits ein kleineres Wiederholungsmuster. (Das Ergebnis von seedUniquifier () sollte bitumgekehrt werden, bevor es im tatsächlichen RNG auf 48 Bit abgeschnitten wird.)
Aber es ist schnell! Und um unnötige Compare-and-Set-Loops zu vermeiden, sollte der Loop-Body schnell sein. Dies erklärt wahrscheinlich die Verwendung dieses spezifischen MLCG, ohne Addition, ohne Xoring, nur eine Multiplikation.
Und das erwähnte Papier enthält eine Liste guter "Multiplikatoren" für c = 0 und m = 2 ^ 64 als 1181783497276652981.
Alles in allem: A für Mühe @ JRE-Entwickler;) Aber es gibt einen Tippfehler. (Aber wer weiß, es sei denn, jemand bewertet es, es besteht die Möglichkeit, dass die fehlende führende 1 tatsächlich das Seeding-RNG verbessert.)
Einige Multiplikatoren sind jedoch definitiv schlechter: "1" führt zu einer konstanten Folge. "2" führt zu einer Einzelbit-Bewegungssequenz (irgendwie korreliert) ...
Die Intersequenzkorrelation für RNGs ist tatsächlich relevant für (Monte-Carlo-) Simulationen, bei denen mehrere Zufallssequenzen instanziiert und sogar parallelisiert werden. Daher ist eine gute Seeding-Strategie erforderlich, um "unabhängige" Simulationsläufe zu erhalten. Daher führt der C ++ 11-Standard das Konzept einer Seed-Sequenz zur Erzeugung nicht korrelierter Seeds ein.
quelle
seedUniquifier
bei Null stecken bleibt.Wenn Sie bedenken, dass die für den Zufallszahlengenerator verwendete Gleichung lautet:
Wobei X (n + 1) die nächste Zahl ist, a der Multiplikator ist, X (n) die aktuelle Zahl ist, c das Inkrement ist und m der Modul ist.
Wenn Sie genauer hinschauen
Random
, werden a, c und m in der Kopfzeile der Klasse definiertund wenn man sich die Methode ansieht, bei der
protected int next(int bits)
die Gleichung implementiert wirdDies impliziert, dass das Verfahren
seedUniquifier()
tatsächlich X (n) erhält oder im ersten Fall bei der Initialisierung X (0), was tatsächlich ist8682522807148012 * 181783497276652981
, dass dieser Wert dann durch den Wert von weiter modifiziert wirdSystem.nanoTime()
. Dieser Algorithmus stimmt mit der obigen Gleichung überein, jedoch mit dem folgenden X (0) =8682522807148012
, a =181783497276652981
, m = 2 ^ 64 und c = 0. Da jedoch der Mod m von durch den langen Überlauf vorgeformt wird, wird die obige Gleichung geradeAuf dem Papier ist der Wert von a =
1181783497276652981
für m = 2 ^ 64, c = 0. Es scheint also nur ein Tippfehler zu sein, und der Wert8682522807148012
für X (0) scheint eine scheinbar zufällig ausgewählte Zahl aus dem Legacy-Code zu sein fürRandom
. Wie hier zu sehen. Aber das Verdienst dieser gewählten Zahlen könnte immer noch gültig sein, aber wie von Thomas B. erwähnt, wahrscheinlich nicht so "gut" wie das in der Zeitung.BEARBEITEN - Die folgenden ursprünglichen Gedanken wurden inzwischen geklärt, können also ignoriert werden, lassen sie jedoch als Referenz
Dies führt mich zu den Schlussfolgerungen:
Der Verweis auf das Papier bezieht sich nicht auf den Wert selbst, sondern auf die Methoden, mit denen die Werte aufgrund der unterschiedlichen Werte von a, c und m erhalten werden
Es ist nur ein Zufall, dass der Wert ansonsten der gleiche ist wie der führende 1 und der Kommentar falsch platziert ist (obwohl er immer noch Schwierigkeiten hat, dies zu glauben).
ODER
Es gab ein ernstes Missverständnis der Tabellen in diesem Artikel, und die Entwickler haben gerade einen zufälligen Wert ausgewählt, da zu dem Zeitpunkt, an dem er multipliziert wird, der Sinn der Verwendung des Tabellenwerts an erster Stelle lag, insbesondere, weil Sie nur Ihren Wert angeben können eigener Startwert in irgendeiner Weise. In diesem Fall werden diese Werte nicht einmal berücksichtigt
Also, um deine Frage zu beantworten
Ja, es könnte eine beliebige Zahl verwendet worden sein. Wenn Sie beim Instantiate Random einen Startwert angeben, verwenden Sie einen anderen Wert. Dieser Wert hat keinen Einfluss auf die Leistung des Generators. Er wird durch die Werte von a, c und m bestimmt, die innerhalb der Klasse fest codiert sind.
quelle
Random
und das zitierte Papier verwickelt, dass ich die ursprüngliche Frage völlig überschritten habe, wird bald bearbeitet, danke.Gemäß dem von Ihnen angegebenen Link haben sie ( nach dem Hinzufügen der fehlenden 1 :) die beste Ausbeute von 2 ^ 64 ausgewählt, da long keine Zahl von 2 ^ 128 haben kann
quelle