2012-11-09 17 views
8

Okay, also ich bin ein wenig Forschung darüber, wie Zufallszahlen mit der Math.random-Methode generiert werden. Bisher habe ich gelernt, dass es mit einem "zufälligen" Startwert beginnt, und dieser Startwert wird in eine komplexe Gleichung eingefügt, um eine Zufallszahl zu erzeugen. Wenn der Samen immer derselbe ist, wird das Ergebnis immer dasselbe sein?Vorhersagen der Samen von Javascript Math.random

Ich habe gehört, dass die Samen für Math.random durch die aktuelle Zeit generiert werden, ist das korrekt? Sie müssen die aktuelle Zeit bis hinunter zu den Millisekunden oder etwas verwenden, denn wenn Sie dies nicht tun würden, würden Sie dasselbe Ergebnis erzielen.

Was genau ist der Samen? Ist es die Zeit wie "10:45" oder die Uhrzeit UND Datum wie "10:45 11/8/12" oder eine Kombination?

Wie kann ich den Seed finden, damit ich die Ausgabe vorhersagen kann?

Das möchte ich in der Lage sein zu stopfen:

alert(Math.floor((Math.random()*10)+1)); 

in meine URL-Leiste und der Lage sein, das Ergebnis vorherzusagen. Ist das möglich?

+0

Der ganze Punkt von 'Math.random()' ist, dass Sie es nicht vorhersagen können (zumindest nicht ohne große Schwierigkeit). –

+1

Gibt es jemanden, der die Quelle für 'v8' liest, um uns eine definitive Antwort zu geben? – TiansHUo

+0

@TiansHUo - Ich las den Quellcode von Rhino und beantwortete die Frage basierend auf dem, was ich gelesen habe: http://StackOverflow.com/a/13303029/783743 –

Antwort

14

Ich schaute durch das Rhino source code, um herauszufinden, welche Pseudozufallsfunktion sie verwenden. Offenbar sind sie fall back zu der Math.random Funktion definiert in der Java standard library.

Die Dokumentation für Math.random sagt:

Gibt einen double-Wert mit einem positiven Vorzeichen, die größer oder gleich 0,0 und weniger als 1,0. Zurückgegebene Werte werden pseudozufällig mit (annähernd) gleichförmiger Verteilung aus diesem Bereich gewählt.

Wenn diese Methode zuerst genannt wird, erzeugt es einen einzigen neuen Pseudo-Zufallszahlengenerator, genau wie durch den Ausdruck

new java.util.Random 

Dieser neue Pseudo-Zufallszahlengenerator für alle Anrufe danach verwendet wird, zu dieser Methode und wird nirgendwo sonst verwendet.

Diese Methode wird ordnungsgemäß synchronisiert, um die korrekte Verwendung durch mehr als einen Thread zu ermöglichen. Wenn jedoch viele Threads Pseudozufallszahlen mit einer großen Rate erzeugen müssen, kann dies die Konkurrenz für jeden Thread reduzieren, um seinen eigenen Pseudozufallszahlengenerator zu haben.

So überprüfte ich die Dokumentation für java.util.Random und gefunden this (für den Standard-Konstruktor):

Erstellt einen neuen Zufallszahlengenerator. Sein Samen wird auf einen Wert initialisiert, basierend auf der aktuellen Zeit:

public Random() { this(System.currentTimeMillis()); } 

zwei zufällige Objekte innerhalb derselben Millisekunde erstellt wird die gleiche Folge von Zufallszahlen haben.

So jetzt wissen wir sicher, dass der Seed die aktuelle Zeit in Millisekunden ist. Auch die Dokumentation der second constructor sagt:

einen neuen Zufallszahlengenerator Erzeugt einen einzigen langen Samen mit:

public Random(long seed) { setSeed(seed); } 

nach Methode Verwendete neben hält den Zustand der Pseudo-Zufallszahlen Generator.

Die documentation für die setSeed Methode sagt:

den Samen dieser Zufallszahlengenerator Legt einen einzigen langen Samen verwendet. Der allgemeine Vertrag von setSeed besteht darin, dass er den Zustand dieses Zufallsgeneratorobjekts so ändert, dass es sich in genau demselben Zustand befindet, als wenn es gerade mit dem Argument seed als Seed erzeugt worden wäre. Das Verfahren wird durch setSeed Klasse Zufalls wie folgt implementiert:

synchronized public void setSeed(long seed) { 
    this.seed = (seed^0x5DEECE66DL) & ((1L << 48) - 1); 
    haveNextNextGaussian = false; 
} 

Die Umsetzung setSeed nach Klasse Zufalls geschieht nur 48 Bits des gegebenen Saatgut verwendet. Im Allgemeinen kann eine überschreibende Methode jedoch alle 64 Bits des langen Arguments als Startwert verwenden.Hinweis: Obwohl der Startwert eine AtomicLong ist, muss diese Methode dennoch synchronisiert werden, um die korrekte Semantik von haveNextNextGaussian zu gewährleisten.

Die actual method verwendet, um die Zufallszahl zu erzeugen, ist nextDouble:

Liefert die nächste Pseudo-Zufalls gleichmäßig doppelten Wert zwischen 0,0 und 1,0 von dieser Zufallszahl-Generator-Sequenz verteilt sind.

Die Umsetzung der nextDouble Funktion ist wie folgt:

public double nextDouble() { 
    return (((long)next(26) << 27) + next(27)) 
     /(double)(1L << 53); 
} 

Offensichtlich es depends auf der next Funktion:

erzeugt die nächste Pseudo-Zufallszahl. Die Unterklasse sollte dies überschreiben, da dies von allen anderen Methoden verwendet wird.

Die Umsetzung der next Funktion ist wie folgt:

synchronized protected int next(int bits) { 
    seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); 
    return (int)(seed >>> (48 - bits)); 
} 

Das ist die Pseudozufallsfunktion ist für Sie suchen.

Dies ist ein linearer kongruenter Pseudozufallszahlengenerator, wie von DH Lehmer definiert und von Donald E. Knuth in The Art of Computer Programming, Volume 2 beschrieben: Wie es in der Dokumentation gesagt Seminumerical Algorithmen, Abschnitt 3.2. 1.

Beachten Sie jedoch, dass dies nur der von Rhino verwendete Zufallsgenerator ist. Andere Implementierungen wie Spidermonkey und V8 können ihre eigenen Pseudozufallszahlengeneratoren haben.

+0

+1, Wunderbare Antwort, so bedeutet dies zumindest ich kann eine Reihe von möglichen Zeiten in Abhängigkeit von der Genauigkeit der Zeit aufzählen, und zumindest konnte ich eine Liste von möglichen Zufallszahlen erhalten (die aus Sicherheitsgründen eindeutig unsicher ist). Aber für die ursprüngliche Frage wahrscheinlich nicht, es sei denn, Sie könnten genau die Millisekunde richtig bekommen. – TiansHUo

+0

@Aadit Sie sind richtig, dass es auf die Umsetzung ankommt, wenn Sie eine Webanwendung mit Javascript erstellen, verwenden verschiedene Webbrowser verschiedene Pseudozufallszahlengeneratoren. Bei bestimmten Anwendungen kann dies zu Schäden führen. Lineare Kongruenzmethoden sind notorisch schlecht darin, alle gewünschten "zufälligen" Eigenschaften zu haben - starke serielle Korrelationen. Siehe http://stackoverflow.com/questions/19507469/math-random-and-web-programming-in-javascript. Große Antwort BTW. – MHH

0

Der Seed ist ein numerischer Wert, so meine Vermutung ist, dass es sein würde, was Sie erhalten, wenn Sie Date.now() (oder new Date().getTime() für ältere Browser aufrufen).

Ich bin jedoch nicht sicher, wenn dieser Seed genommen wird, oder wenn der Seed auf die aktuelle Seite isoliert oder für den gesamten Browserprozess üblich ist. Vorhersage von Zufallszahlen wird als sehr schwer oder unmöglich angesehen, das ist der springende Punkt, dass sie zufällig sind.

6

Es ist wahrscheinlich, dass mehr als die Millisekundenzahl im Seed enthalten ist, da Sie Math.random() mehrmals in derselben Millisekunde aufrufen können und jedes Mal einen anderen Wert zurückgibt.

for (var i = 0; i < 3; i++) { 
    console.log(Math.random(), (new Date()).getTime()); 
}; 

Meine Ausgabe:

0.0617244818713516 1352433709108 
0.8024995378218591 1352433709108 
0.2409922298975289 1352433709108 

Wenn ich es Implementierung wurde, ich könnte den anfänglichen Samen basierte auf einer Millisekundenzählwert machen, und fügen Sie dann 1 jedes Mal, es heißt, so dass Sie nicht bekommen würden der gleiche Startwert zweimal.

Hier ist eine 100% genaue Art und Weise die Ausgabe von Math.random() der Vorhersage:

Math.random = function() { return .5; }; 

Jetzt wird Math.random() immer .5 zurück.

+0

@ 43.52.4D. Es gibt einen Weg, das herauszufinden. Fangt an es zu tun, in zehn Jahren werden wir die Antwort haben, das heißt, ob es möglich ist oder nicht ... Seid ihr echt ?! – gdoron

+0

Hier ist der Code hinter Chrome's Math.random(): http://code.google.com/p/v8/source/browse/trunk/src/v8.cc#170 Es sieht so aus, als würde es im Grunde genommen die Ihres Systems benutzen Zufallszahlengenerator. Wie gut es letztendlich ist, hängt vom RNG Ihres Betriebssystems ab. – evan

0

Nein, Sie können den Seed nicht vorhersagen, aber Sie können vorsorglich genug Zahlen generieren, um eine Übereinstimmung genau zu bruten.

Wie auch immer, beginnend mit dem Lesen der Wiki-Seite auf RNG - http://en.wikipedia.org/wiki/Random_number_generation, der Blick auf die praktischen Implementierungen von PRNG.