Ist es möglich, den Zufallszahlengenerator (Math.random) in Javascript zu setzen?
javascript
random
weinerlich
quelle
quelle
Antworten:
Nein, ist es nicht, aber es ist ziemlich einfach, einen eigenen Generator zu schreiben oder noch besser einen vorhandenen zu verwenden. Check out: diese verwandte Frage .
Weitere Informationen zum Seeding finden Sie auch im Blog von David Bau .
quelle
HINWEIS: Trotz (oder vielmehr wegen) Prägnanz und offensichtlicher Eleganz ist dieser Algorithmus in Bezug auf die Zufälligkeit keineswegs von hoher Qualität. Suchen Sie nach den in dieser Antwort aufgeführten, um bessere Ergebnisse zu erzielen.
(Ursprünglich angepasst von einer cleveren Idee, die in einem Kommentar zu einer anderen Antwort präsentiert wurde.)
Sie können einstellen
seed
eine beliebige Zahl festlegen. Vermeiden Sie einfach Null (oder ein Vielfaches von Math.PI).Die Eleganz dieser Lösung beruht meiner Meinung nach auf dem Fehlen jeglicher "magischer" Zahlen (neben 10000, was ungefähr der Mindestanzahl von Ziffern entspricht, die Sie wegwerfen müssen, um ungerade Muster zu vermeiden - siehe Ergebnisse mit Werten 10 , 100 , 1000 ). Kürze ist auch schön.
Es ist etwas langsamer als Math.random () (um den Faktor 2 oder 3), aber ich glaube, es ist ungefähr so schnell wie jede andere in JavaScript geschriebene Lösung.
quelle
Ich habe eine Reihe guter, kurzer und schneller Funktionen des Pseudozufallszahlengenerators (PRNG) in einfachem JavaScript implementiert . Alle von ihnen können ausgesät werden und liefern gute Qualitätszahlen.
Achten Sie zunächst darauf, Ihre PRNGs ordnungsgemäß zu initialisieren. Die meisten der Generatoren haben unten keine integrierte Prozedur Samen Erzeugen (der Einfachheit halber), aber akzeptieren einen oder mehrere 32-Bit - Werte als Anfangszustand des PRNG. Ähnliche Keime (z. B. ein einfacher Keim von 1 und 2) können Korrelationen in schwächeren PRNGs verursachen, was dazu führt, dass die Ausgabe ähnliche Eigenschaften aufweist (z. B. zufällig erzeugte Niveaus sind ähnlich). Um dies zu vermeiden, empfiehlt es sich, PRNGs mit einem gut verteilten Seed zu initialisieren.
Glücklicherweise sind Hash-Funktionen sehr gut darin, aus kurzen Strings Seeds für PRNGs zu generieren. Eine gute Hash-Funktion führt zu sehr unterschiedlichen Ergebnissen, selbst wenn zwei Zeichenfolgen ähnlich sind. Hier ist ein Beispiel, das auf der Mischfunktion von MurmurHash3 basiert:
Jeder nachfolgende Aufruf der Rückgabefunktion von
xmur3
erzeugt einen neuen "zufälligen" 32-Bit-Hashwert, der als Startwert in einem PRNG verwendet wird. So können Sie es verwenden:Alternativ können Sie einfach einige Dummy-Daten auswählen, mit denen der Startwert aufgefüllt werden soll, und den Generator einige Male (12 bis 20 Iterationen) vorschieben, um den Anfangszustand gründlich zu mischen. Dies wird häufig in Referenzimplementierungen von PRNGs gesehen, begrenzt jedoch die Anzahl der Anfangszustände.
Die Ausgabe dieser PRNG-Funktionen erzeugt eine positive 32-Bit-Zahl (0 bis 2 32 -1), die dann in eine Gleitkommazahl zwischen 0-1 (0 einschließlich, 1 exklusiv) umgewandelt wird, was entspricht
Math.random()
, wenn Sie Zufallszahlen wünschen Lesen Sie diesen Artikel über MDN . Wenn Sie nur die Rohbits möchten, entfernen Sie einfach die letzte Teilungsoperation.Eine andere Sache zu beachten sind die Einschränkungen von JS. Zahlen können nur ganze Ganzzahlen mit einer Auflösung von bis zu 53 Bit darstellen. Bei Verwendung von bitweisen Operationen wird dies auf 32 reduziert. Dies macht es schwierig, in C oder C ++ geschriebene Algorithmen zu implementieren, die 64-Bit-Zahlen verwenden. Für die Portierung von 64-Bit-Code sind Shims erforderlich, die die Leistung drastisch reduzieren können. Der Einfachheit und Effizienz halber habe ich nur Algorithmen in Betracht gezogen, die 32-Bit-Mathematik verwenden, da diese direkt mit JS kompatibel ist.
sfc32 (Einfacher schneller Zähler)
sfc32 ist Teil der PractRand- Suite zum Testen von Zufallszahlen (die es natürlich besteht). sfc32 hat einen 128-Bit-Status und ist in JS sehr schnell.
Mulberry32
Mulberry32 ist ein einfacher Generator mit einem 32-Bit-Status, der jedoch extrem schnell und von guter Qualität ist (der Autor gibt an, dass er alle Tests der gjrand- Testsuite besteht und einen vollständigen Zeitraum von 2 bis 32 hat, den ich jedoch nicht überprüft habe).
Ich würde dies empfehlen, wenn Sie nur ein einfaches, aber anständiges PRNG benötigen und keine Milliarden von Zufallszahlen benötigen (siehe Geburtstagsproblem ).
xoshiro128 **
Seit Mai 2018 ist xoshiro128 ** das neue Mitglied der Xorshift-Familie von Vigna / Blackman (der auch xoroshiro geschrieben hat, das in Chrome verwendet wird). Es ist der schnellste Generator, der einen 128-Bit-Status bietet.
Die Autoren behaupten, dass es Zufälligkeitstests gut besteht ( wenn auch mit Einschränkungen ). Andere Forscher haben darauf hingewiesen, dass einige Tests in TestU01 (insbesondere LinearComp und BinaryRank) nicht bestanden wurden. In der Praxis sollte es keine Probleme verursachen, wenn Floats verwendet werden (wie diese Implementierungen), kann jedoch Probleme verursachen, wenn Sie sich auf die rohen Low-Bits verlassen.
JSF (Jenkins 'Small Fast)
Dies ist JSF oder 'smallprng' von Bob Jenkins (2007), dem Typ, der ISAAC und SpookyHash gemacht hat . Es geht PractRand Tests und soll recht schnell, wenn auch nicht so schnell wie SFC sein.
LCG (auch bekannt als Lehmer / Park-Miller RNG oder MCG)
LCG ist extrem schnell und einfach, aber die Qualität seiner Zufälligkeit ist so gering, dass eine unsachgemäße Verwendung tatsächlich Fehler in Ihrem Programm verursachen kann! Trotzdem ist es deutlich besser als einige Antworten, die vorschlagen,
Math.sin
oder zu verwendenMath.PI
! Es ist allerdings ein Einzeiler, was schön ist :).Diese Implementierung wird als Minimalstandard- RNG bezeichnet, wie von Park-Miller 1988 und 1993 vorgeschlagen und in C ++ 11 als implementiert
minstd_rand
. Beachten Sie, dass der Status 31 Bit ist (31 Bit ergeben 2 Milliarden mögliche Zustände, 32 Bit ergeben das Doppelte). Dies ist genau die Art von PRNG, die andere zu ersetzen versuchen!Es wird funktionieren, aber ich würde es nicht verwenden, es sei denn, Sie brauchen wirklich Geschwindigkeit und kümmern sich nicht um die Zufallsqualität (was ist überhaupt zufällig?). Ideal für einen Game Jam oder eine Demo oder so. LCGs leiden unter Samenkorrelationen, daher ist es am besten, das erste Ergebnis zu verwerfen einer LCG . Und wenn Sie darauf bestehen, eine LCG zu verwenden, kann das Hinzufügen eines Inkrementwerts die Ergebnisse verbessern, aber es ist wahrscheinlich eine Übung der Sinnlosigkeit, wenn es viel bessere Optionen gibt.
Es scheint andere Multiplikatoren zu geben, die einen 32-Bit-Zustand (vergrößerter Zustandsraum) anbieten:
Diese LCG-Werte stammen von: P. L'Ecuyer: Eine Tabelle von linearen Kongruenzgeneratoren unterschiedlicher Größe und guter Gitterstruktur, 30. April 1997.
quelle
seed = (seed * 185852 + 1) % 34359738337
.Math.imul
ermöglicht einen Überlauf wie bei der Multiplikation in C mit 32-Bit-Ganzzahlen. Was Sie vorschlagen, ist eine LCG, die den gesamten Bereich des JS-Integer-Raums nutzt. Dies ist definitiv auch ein interessantes Gebiet, das es zu erkunden gilt. :)Nein, aber hier ist ein einfacher Pseudozufallsgenerator, eine Implementierung von Multiply-with-Carry, die ich aus Wikipedia übernommen habe (wurde seitdem entfernt):
EDIT: Behebung der
Startfunktion durch Zurücksetzen von m_z EDIT2: Schwerwiegende Implementierungsfehler wurden behoben
quelle
seed
Funktion setzt den Zufallsgenerator nicht zurück, da diemz_z
Variable beimrandom()
Aufruf geändert wird. Setzen Sie dahermz_z = 987654321
(oder einen anderen Wert) inseed
m_w
, nichtm_z
. 2) Beidem_w
und werdenm_z
basierend auf ihren vorherigen Werten geändert, sodass das Ergebnis geändert wird.Der Algorithmus von Antti Sykäri ist nett und kurz. Ich habe anfangs eine Variation vorgenommen, die Math.random von Javascript ersetzte, wenn Sie Math.seed (s) aufrufen, aber dann bemerkte Jason, dass die Rückgabe der Funktion besser wäre:
Dies gibt Ihnen eine weitere Funktionalität, die Javascript nicht hat: mehrere unabhängige Zufallsgeneratoren. Dies ist besonders wichtig, wenn mehrere wiederholbare Simulationen gleichzeitig ausgeführt werden sollen.
quelle
Math.random
, dass Sie mehrere unabhängige Generatoren haben, oder?Math.seed(42);
es setzt die Funktion, wenn Sie also tunvar random = Math.seed(42); random(); random();
erhalten Sie0.70...
, dann0.38...
. Wenn Sie es zurücksetzen, indem Sievar random = Math.seed(42);
erneut anrufen, erhaltenrandom()
Sie beim nächsten Anruf0.70...
erneut und beim nächsten Mal0.38...
erneut.random
anstatt eine native Javascript-Funktion zu überschreiben. Das ÜberschreibenMath.random
kann dazu führen, dass der JIST-Compiler den gesamten Code nicht optimiert.Bitte sehen Sie Pierre L'Ecuyers Arbeiten, die bis in die späten 1980er und frühen 1990er Jahre zurückreichen. Es gibt auch andere. Wenn Sie kein Experte sind, ist es ziemlich gefährlich, selbst einen (Pseudo-) Zufallszahlengenerator zu erstellen, da die Wahrscheinlichkeit hoch ist, dass die Ergebnisse statistisch nicht zufällig sind oder nur einen kurzen Zeitraum haben. Pierre (und andere) haben einige gute (Pseudo-) Zufallszahlengeneratoren zusammengestellt, die einfach zu implementieren sind. Ich benutze einen seiner LFSR-Generatoren.
https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf
Phil Troy
quelle
Wenn Sie einige der vorherigen Antworten kombinieren, ist dies die gesetzte Zufallsfunktion, nach der Sie suchen:
quelle
Math.seed(0)()
return0.2322845458984375
undMath.seed(1)()
return0.23228873685002327
. Beidesm_w
undm_z
je nach Samen zu ändern scheint zu helfen.var m_w = 987654321 + s; var m_z = 123456789 - s;
erzeugt eine schöne Verteilung der ersten Werte mit verschiedenen Samen.Es ist ganz einfach, einen eigenen Pseudozufallsgenerator zu schreiben.
Der Vorschlag von Dave Scotese ist nützlich, aber, wie andere betonten, nicht ganz gleichmäßig verteilt.
Es liegt jedoch nicht an den ganzzahligen Argumenten der Sünde. Es liegt einfach an der Reichweite der Sünde, die zufällig eine eindimensionale Projektion eines Kreises ist. Wenn Sie stattdessen den Winkel des Kreises nehmen würden, wäre er gleichmäßig.
Verwenden Sie also anstelle von sin (x) arg (exp (i * x)) / (2 * PI).
Wenn Ihnen die lineare Reihenfolge nicht gefällt, mischen Sie sie ein wenig mit xor. Der eigentliche Faktor spielt auch keine Rolle.
Um n Pseudozufallszahlen zu erzeugen, könnte man den folgenden Code verwenden:
Bitte beachten Sie auch, dass Sie keine Pseudozufallssequenzen verwenden können, wenn echte Entropie benötigt wird.
quelle
Viele Leute, die heutzutage einen Startwertgenerator in Javascript benötigen, verwenden das Startwert-Zufallsmodul von David Bau .
quelle
Math.random
Nein, aber die Ran- Bibliothek löst dies. Es hat fast alle denkbaren Verteilungen und unterstützt die Erzeugung von gesetzten Zufallszahlen. Beispiel:quelle
Ich habe eine Funktion geschrieben, die eine gesetzte Zufallszahl zurückgibt. Sie verwendet Math.sin, um eine lange Zufallszahl zu haben, und verwendet den Startwert, um Zahlen daraus auszuwählen.
Verwenden :
Es gibt Ihre gesetzte Zahl zurück. Der erste Parameter ist ein beliebiger Zeichenfolgenwert. dein Same. Der zweite Parameter gibt an, wie viele Ziffern zurückgegeben werden.
quelle
Ein einfacher Ansatz für einen festen Samen:
quelle
Für eine Zahl zwischen 0 und 100.
quelle
Math.random
, dass jedes Mal, wennMath.random
mit demselben Samen gesät wird, dieselbe aufeinanderfolgende Reihe von Zufallszahlen erzeugt wird. Bei dieser Frage geht es nicht um die tatsächliche Verwendung / Demonstration vonMath.random
.