La Math.random()
fonction JavaScript renvoie une valeur aléatoire entre 0 et 1, automatiquement amorcée en fonction de l'heure actuelle (similaire à Java je crois). Cependant, je ne pense pas qu'il y ait un moyen de créer votre propre semence pour cela.
Comment puis-je créer un générateur de nombres aléatoires pour lequel je peux fournir ma propre valeur de départ, afin de pouvoir le faire produire une séquence répétable de (pseudo) nombres aléatoires?
javascript
random
seed
scunliffe
la source
la source
Réponses:
Une option est http://davidbau.com/seedrandom qui est un remplacement instantané Math.random () basé sur RC4 avec de belles propriétés.
la source
Si vous n'avez pas besoin de la capacité d'amorçage, utilisez
Math.random()
et créez simplement des fonctions d'assistance autour de celle-ci (par exemplerandRange(start, end)
).Je ne sais pas quel RNG vous utilisez, mais il est préférable de le connaître et de le documenter afin que vous soyez conscient de ses caractéristiques et de ses limites.
Comme l'a dit Starkii, Mersenne Twister est un bon PRNG, mais ce n'est pas facile à mettre en œuvre. Si vous voulez le faire vous-même, essayez d'implémenter un LCG - c'est très facile, a des qualités aléatoires décentes (pas aussi bonnes que Mersenne Twister), et vous pouvez utiliser certaines des constantes populaires.
EDIT: considérez les excellentes options de cette réponse pour les implémentations RNG courtes, y compris une option LCG.
la source
this.a * this.state
entraînera probablement un nombre supérieur à 2 ^ 53. Le résultat est une plage de production limitée, et pour certaines semences peut-être une période très courte. De plus, en général, l'utilisation d'une puissance de deux pourm
aboutir à des modèles assez évidents, lorsque vous dépensez une opération de module plutôt qu'une simple troncature de toute façon, il n'y a aucune raison de ne pas utiliser de prime.Si vous souhaitez pouvoir spécifier la valeur de départ, il vous suffit de remplacer les appels à
getSeconds()
etgetMinutes()
. Vous pouvez passer un int et utiliser la moitié du mod 60 pour la valeur des secondes et l'autre moitié du modulo 60 pour vous donner l'autre partie.Cela étant dit, cette méthode ressemble à des ordures. Faire une bonne génération de nombres aléatoires est très difficile. Le problème évident avec ceci est que la graine de nombre aléatoire est basée sur les secondes et les minutes. Pour deviner la graine et recréer votre flux de nombres aléatoires, il suffit d'essayer 3600 combinaisons de secondes et de minutes différentes. Cela signifie également qu'il n'y a que 3600 graines différentes possibles. Cela peut être corrigé, mais je me méfierais de ce RNG depuis le début.
Si vous souhaitez utiliser un meilleur RNG, essayez le Mersenne Twister . C'est un RNG bien testé et assez robuste avec une orbite énorme et d'excellentes performances.
EDIT: Je devrais vraiment avoir raison et faire référence à cela comme un générateur de nombres pseudo aléatoires ou PRNG.
la source
J'utilise un port JavaScript du Mersenne Twister: https://gist.github.com/300494 Il vous permet de définir la graine manuellement. De plus, comme mentionné dans d'autres réponses, le Mersenne Twister est un très bon PRNG.
la source
Le code que vous avez listé ressemble à un Lehmer RNG . Si tel est le cas, alors
2147483647
est le plus grand entier signé de 32 bits,2147483647
est le plus grand premier de 32 bits et48271
est un multiplicateur de période complète qui est utilisé pour générer les nombres.Si cela est vrai, vous pouvez modifier
RandomNumberGenerator
pour prendre un paramètre supplémentaireseed
, puis définirthis.seed
surseed
; mais vous devez faire attention à vous assurer que la graine aboutit à une bonne distribution de nombres aléatoires (Lehmer peut être bizarre comme ça) - mais la plupart des graines iront bien.la source
Ce qui suit est un PRNG qui peut être alimenté avec une graine personnalisée. L'appel
SeedRandom
renverra une fonction de générateur aléatoire.SeedRandom
peut être appelée sans argument afin d'amorcer la fonction aléatoire retournée avec l'heure actuelle, ou elle peut être appelée avec 1 ou 2 inters non négatifs comme arguments afin de l'amorcer avec ces entiers. En raison de la précision du point flottant, un ensemencement avec une seule valeur ne permettra au générateur de démarrer que dans l'un des 2 ^ 53 états différents.La fonction de générateur aléatoire renvoyée prend 1 argument entier nommé
limit
, la limite doit être comprise entre 1 et 4294965886, la fonction retournera un nombre compris entre 0 et limit-1.Exemple d'utilisation:
Ce générateur présente les propriétés suivantes:
mod
valeurs sont des nombres premiers, il n'y a pas de modèle simple dans la sortie, quelle que soit la limite choisie. Ceci est différent de certains PRNG plus simples qui présentent des modèles assez systématiques.la source
for (var i = 0; i < 400; i++) { console.log("input: (" + i * 245 + ", " + i * 553 + ") | output: " + SeedRandom(i * 245, i * 553)(20)); }
Si vous programmez en Typescript, j'ai adapté l'implémentation Mersenne Twister qui a été apportée dans la réponse de Christoph Henkelmann à ce fil en tant que classe dactylographiée:
vous pouvez ensuite l'utiliser comme suit:
vérifiez la source pour plus de méthodes.
la source
J'ai trouvé ce code en train de tourner et il semble fonctionner correctement pour obtenir un nombre aléatoire, puis utiliser la graine par la suite, mais je ne suis pas tout à fait sûr du fonctionnement de la logique (par exemple, d'où viennent les numéros 2345678901, 48271 et 2147483647).
la source
RandomNumberGenerator
etnextRandomNumber
datent en fait de 1996. Il est censé être un Lehmer / LCG RNG. Il utilise des mathématiques intelligentes pour effectuer de l'arithmétique modulo sur des entiers 32 bits qui seraient autrement trop petits pour contenir des valeurs intermédiaires. Le fait est que JavaScript n'implémente pas les entiers 32 bits, mais plutôt les flottants 64 bits, et puisque la division n'est pas une division entière comme ce code suppose que le résultat n'est pas un générateur Lehmer. Cela produit des résultats qui semblent aléatoires, mais les garanties d'un générateur Lehmer ne s'appliquent pas.createRandomNumber
fonction est un ajout ultérieur, elle fait à peu près tout de travers, notamment elle instancie un nouveau RNG chaque fois qu'elle est appelée, ce qui signifie que les appels en succession rapide utiliseront tous le même float. Dans le code donné, il est presque impossible'a'
d'être associé à autre chose que'1'
et'red'
.OK, voici la solution sur laquelle j'ai choisi.
Vous créez d'abord une valeur de départ à l'aide de la fonction "newseed ()". Ensuite, vous passez la valeur de départ à la fonction "srandom ()". Enfin, la fonction "srandom ()" renvoie une valeur pseudo aléatoire entre 0 et 1.
Le point crucial est que la valeur de départ est stockée dans un tableau. S'il s'agissait simplement d'un entier ou d'un flottant, la valeur serait écrasée chaque fois que la fonction était appelée, car les valeurs des entiers, des flottants, des chaînes, etc. sont stockées directement dans la pile par rapport aux pointeurs comme dans le cas des tableaux et d'autres objets. Ainsi, il est possible que la valeur de la graine reste persistante.
Enfin, il est possible de définir la fonction "srandom ()" de telle sorte que ce soit une méthode de l'objet "Math", mais je vous laisse le soin de comprendre. ;)
Bonne chance!
JavaScript:
Lua 4 (mon environnement cible personnel):
la source
seedobj[0] * seedobja
entraînera probablement un nombre supérieur à 2 ^ 53. Le résultat est une plage de production limitée, et pour certaines semences peut-être une période très courte.