Die JavaScript- Math.random()
Funktion gibt einen zufälligen Wert zwischen 0 und 1 zurück, der basierend auf der aktuellen Zeit automatisch gesetzt wird (ähnlich wie Java, glaube ich). Ich glaube jedoch nicht, dass es eine Möglichkeit gibt, einen eigenen Samen dafür zu setzen.
Wie kann ich einen Zufallszahlengenerator erstellen, für den ich meinen eigenen Startwert angeben kann, damit er eine wiederholbare Folge von (Pseudo-) Zufallszahlen erzeugt?
javascript
random
seed
scunliffe
quelle
quelle
Antworten:
Eine Option ist http://davidbau.com/seedrandom , ein setzbarer RC4-basierter Math.random () - Drop-In-Ersatz mit netten Eigenschaften.
quelle
Wenn Sie die Seeding-Funktion nicht benötigen, verwenden
Math.random()
und bauen Sie einfach Hilfsfunktionen darum herum (z. B.randRange(start, end)
).Ich bin nicht sicher, welches RNG Sie verwenden, aber es ist am besten, es zu kennen und zu dokumentieren, damit Sie sich seiner Eigenschaften und Einschränkungen bewusst sind.
Wie Starkii sagte, ist Mersenne Twister ein gutes PRNG, aber es ist nicht einfach zu implementieren. Wenn Sie es selbst tun möchten, versuchen Sie, ein LCG zu implementieren - es ist sehr einfach, hat anständige Zufallsqualitäten (nicht so gut wie Mersenne Twister) und Sie können einige der gängigen Konstanten verwenden.
BEARBEITEN: Berücksichtigen Sie bei dieser Antwort die großartigen Optionen für kurze RNG-Implementierungen, einschließlich einer LCG-Option.
quelle
this.a * this.state
wahrscheinlich zu einer Zahl größer als 2 ^ 53 führt. Das Ergebnis ist ein begrenzter Ausgabebereich und für einige Samen möglicherweise ein sehr kurzer Zeitraum.m
Wenn Sie im Allgemeinen eine Zweierpotenz verwenden, um einige ziemlich offensichtliche Muster zu erhalten, gibt es keinen Grund, keine Primzahl zu verwenden, wenn Sie eine Moduloperation anstelle einer einfachen Kürzung aufwenden.Wenn Sie den Startwert angeben möchten, müssen Sie nur die Aufrufe von
getSeconds()
und ersetzengetMinutes()
. Sie könnten ein int übergeben und die Hälfte davon mod 60 für den Sekundenwert und die andere Hälfte modulo 60 verwenden, um Ihnen den anderen Teil zu geben.Davon abgesehen sieht diese Methode wie Müll aus. Die richtige Erzeugung von Zufallszahlen ist sehr schwierig. Das offensichtliche Problem dabei ist, dass der Zufallszahlen-Seed auf Sekunden und Minuten basiert. Um den Startwert zu erraten und Ihren Zufallszahlenstrom neu zu erstellen, müssen Sie nur 3600 verschiedene Sekunden- und Minutenkombinationen ausprobieren. Dies bedeutet auch, dass es nur 3600 verschiedene mögliche Samen gibt. Dies ist korrigierbar, aber ich wäre von Anfang an misstrauisch gegenüber diesem RNG.
Wenn Sie ein besseres RNG verwenden möchten, probieren Sie den Mersenne Twister . Es ist ein gut getestetes und ziemlich robustes RNG mit einer riesigen Umlaufbahn und einer hervorragenden Leistung.
EDIT: Ich sollte wirklich korrekt sein und dies als Pseudo-Zufallszahlengenerator oder PRNG bezeichnen.
quelle
Ich verwende einen JavaScript-Port des Mersenne Twister: https://gist.github.com/300494 Damit können Sie den Startwert manuell festlegen. Wie in anderen Antworten erwähnt, ist der Mersenne Twister auch ein wirklich guter PRNG.
quelle
Der Code, den Sie aufgelistet haben, sieht aus wie ein Lehmer RNG . Wenn dies der Fall ist,
2147483647
ist dies die größte 32-Bit-Ganzzahl mit Vorzeichen,2147483647
die größte 32-Bit-Primzahl und48271
ein Vollzeitmultiplikator, der zum Generieren der Zahlen verwendet wird.Wenn dies der Fall ist, können Sie ändern
RandomNumberGenerator
in einem zusätzlichen Parameter zu nehmenseed
, und stellen Sie dannthis.seed
aufseed
; Aber Sie müssten vorsichtig sein, um sicherzustellen, dass der Samen zu einer guten Verteilung der Zufallszahlen führt (Lehmer kann so seltsam sein) - aber die meisten Samen sind in Ordnung.quelle
Das Folgende ist ein PRNG, dem ein benutzerdefiniertes Saatgut zugeführt werden kann. Beim Aufrufen
SeedRandom
wird eine Zufallsgeneratorfunktion zurückgegeben.SeedRandom
kann ohne Argumente aufgerufen werden, um die zurückgegebene Zufallsfunktion mit der aktuellen Zeit zu setzen, oder es kann entweder mit 1 oder 2 nicht negativen inters als Argumente aufgerufen werden, um sie mit diesen ganzen Zahlen zu setzen. Aufgrund der Gleitkommagenauigkeit kann beim Seeding mit nur 1 Wert der Generator nur in einen von 2 ^ 53 verschiedenen Zuständen versetzt werden.Die zurückgegebene Zufallsgeneratorfunktion verwendet 1 benanntes Ganzzahlargument
limit
. Der Grenzwert muss im Bereich von 1 bis 4294965886 liegen. Die Funktion gibt eine Zahl im Bereich von 0 bis Grenzwert 1 zurück.Anwendungsbeispiel:
Dieser Generator weist folgende Eigenschaften auf:
mod
Werte Primzahlen sind, gibt es kein einfaches Muster in der Ausgabe, unabhängig von der gewählten Grenze. Dies ist anders als bei einigen einfacheren PRNGs, die einige recht systematische Muster aufweisen.quelle
for (var i = 0; i < 400; i++) { console.log("input: (" + i * 245 + ", " + i * 553 + ") | output: " + SeedRandom(i * 245, i * 553)(20)); }
Wenn Sie in Typescript programmieren, habe ich die Mersenne Twister-Implementierung angepasst, die in Christoph Henkelmanns Antwort auf diesen Thread als Typoskript-Klasse enthalten war:
Sie können es dann wie folgt verwenden:
Überprüfen Sie die Quelle auf weitere Methoden.
quelle
Ich habe festgestellt, dass dieser Code herumwirbelt, und es scheint gut zu funktionieren, um eine Zufallszahl zu erhalten und anschließend den Startwert zu verwenden, aber ich bin mir nicht ganz sicher, wie die Logik funktioniert (z. B. woher die Zahlen 2345678901, 48271 und 2147483647 stammen).
quelle
RandomNumberGenerator
undnextRandomNumber
Funktionen stammen tatsächlich aus dem Jahr 1996. Es soll sich um ein Lehmer / LCG RNG handeln. Es verwendet einige clevere Mathematik, um Modulo-Arithmetik für 32-Bit-Ganzzahlen durchzuführen, die sonst zu klein wären, um einige Zwischenwerte zu enthalten. Die Sache ist, dass JavaScript keine 32-Bit-Ganzzahlen implementiert, sondern 64-Bit-Gleitkommazahlen, und da die Division keine Ganzzahldivision ist, wie dieser Code voraussetzt, ist das Ergebnis kein Lehmer-Generator. Es führt zwar zu zufälligen Ergebnissen, die Garantien eines Lehmer-Generators gelten jedoch nicht.createRandomNumber
Funktion ist eine spätere Ergänzung, sie macht so ziemlich alles falsch, insbesondere instanziiert sie jedes Mal ein neues RNG, wenn sie aufgerufen wird, was bedeutet, dass Aufrufe in schneller Folge alle denselben Float verwenden. In dem gegebenen Code ist es fast unmöglich'a'
, mit etwas anderem als'1'
und gepaart zu werden'red'
.OK, hier ist die Lösung, für die ich mich entschieden habe.
Zuerst erstellen Sie einen Startwert mit der Funktion "newseed ()". Anschließend übergeben Sie den Startwert an die Funktion "srandom ()". Schließlich gibt die Funktion "srandom ()" einen Pseudozufallswert zwischen 0 und 1 zurück.
Das entscheidende Bit ist, dass der Startwert in einem Array gespeichert wird. Wenn es einfach eine Ganzzahl oder ein Gleitkommawert wäre, würde der Wert bei jedem Aufruf der Funktion überschrieben, da die Werte von Ganzzahlen, Gleitkommazahlen, Zeichenfolgen usw. direkt im Stapel gespeichert werden und nicht nur die Zeiger, wie im Fall von Arrays und andere Objekte. Somit ist es möglich, dass der Wert des Samens persistent bleibt.
Schließlich ist es möglich, die Funktion "srandom ()" so zu definieren, dass es sich um eine Methode des "Math" -Objekts handelt, aber das überlasse ich Ihnen, um es herauszufinden. ;)
Viel Glück!
JavaScript:
Lua 4 (meine persönliche Zielumgebung):
quelle
seedobj[0] * seedobja
wahrscheinlich zu einer Zahl größer als 2 ^ 53 führt. Das Ergebnis ist ein begrenzter Ausgabebereich und für einige Samen möglicherweise ein sehr kurzer Zeitraum.