188 votes

Seedable générateur de nombres aléatoires du JavaScript

Le JavaScript Math.random() fonction renvoie une valeur aléatoire entre 0 et 1, automatiquement graines en fonction de l'heure (similaire à Java, je crois). Cependant, je ne pense pas qu'il y a moyen de définir vous-mêmes graines.

Comment puis-je faire un générateur de nombre aléatoire que je peux fournir mon propre valeur de départ, de sorte que je peux l'avoir à produire un modèle de séquence de (pseudo)aléatoire de numéros?

156voto

David Bau Points 576

Une option est http://davidbau.com/seedrandom qui est un seedable remplacement Math.Random () axée sur la RC4 avec belles propriétés.

30voto

orip Points 28225

si vous n'avez pas besoin de semis capacité, il suffit d'utiliser Math.random() et de construire des fonctions d'assistance autour d'elle (par exemple. randRange(start, end)).

Je ne suis pas sûr de ce que RNG que vous utilisez, mais il est préférable de les connaître et de les documenter afin que vous êtes conscient de ses caractéristiques et des limites.

Comme Starkii dit, Mersenne Twister est un bon GÉNÉRATEUR, mais il n'est pas facile à mettre en œuvre. Si vous voulez le faire vous-même essayez de mettre en œuvre un LCG - il est très facile, s'avère aléatoire qualités (pas aussi bon que Mersenne Twister), et vous pouvez utiliser les constantes.

function RNG(seed) {
  // LCG using GCC's constants
  this.m = 0x80000000; // 2**31;
  this.a = 1103515245;
  this.c = 12345;

  this.state = seed ? seed : Math.floor(Math.random() * (this.m-1));
}
RNG.prototype.nextInt = function() {
  this.state = (this.a * this.state + this.c) % this.m;
  return this.state;
}
RNG.prototype.nextFloat = function() {
  // returns in range [0,1]
  return this.nextInt() / (this.m - 1);
}
RNG.prototype.nextRange = function(start, end) {
  // returns in range [start, end): including start, excluding end
  // can't modulu nextInt because of weak randomness in lower bits
  var rangeSize = end - start;
  var randomUnder1 = this.nextInt() / this.m;
  return start + Math.floor(randomUnder1 * rangeSize);
}
RNG.prototype.choice = function(array) {
  return array[this.nextRange(0, array.length)];
}

var rng = new RNG(20);
for (var i = 0; i < 10; i++)
  console.log(rng.nextRange(10,50));

var digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
for (var i = 0; i < 10; i++)
  console.log(rng.choice(digits));

23voto

Starkii Points 729

Si vous voulez être en mesure de spécifier la valeur de départ, il vous suffit de remplacer les appels à l' getSeconds() et getMinutes(). Vous pouvez passer dans un int et utiliser la moitié de ce mod 60 ans pour les secondes, la valeur et l'autre moitié modulo 60 pour vous donner l'autre partie.

Cela étant dit, cette méthode recherche comme des ordures. Faire bonne génération de nombre aléatoire est très dur. Le problème évident est que la série de nombres aléatoires est basé sur les secondes et les minutes. De deviner la graine et recréer votre flux de nombres aléatoires ne nécessite essayer 3600 différents des secondes et des minutes de combinaisons. Cela signifie également qu'il y a seulement 3600 différents types de graines. C'est corrigé, mais je serais méfiant de ce RNG depuis le début.

Si vous souhaitez utiliser une meilleure RNG, essayez de le Mersenne Twister. Il est bien testé et assez robuste RNG avec un immense orbite et une excellente performance.

EDIT: j'ai vraiment devrait être correct et reportez-vous à ce que d'un Pseudo Random Number Generator ou PRNG.

"Toute personne qui utilise l'arithmétique des méthodes pour produire des nombres aléatoires est dans un état de péché."
--- John von Neumann

14voto

J’utilise un port JavaScript de la Mersenne Twister : https://gist.github.com/300494 il vous permet de régler manuellement les semences. En outre, comme mentionné dans d’autres réponses, le Mersenne Twister est un vraiment bon PRNG.

9voto

mipadi Points 135410

Le code que vous avez énumérés ressemble à une sorte de Lehmer RNG. Si c'est le cas, alors 2147483647 est le plus grand entier signé 32 bits, 2147483647 est le plus grand de 32 bits en premier, et 48271 est une période complète multiplicateur qui est utilisé pour générer les nombres.

Si cela est vrai, vous pouvez modifier RandomNumberGenerator à prendre dans un paramètre supplémentaire, seed, puis définissez this.seed de seed; mais vous devez être prudent et assurez-vous que la graine se traduirait par une bonne répartition des nombres aléatoires (Lehmer peut être bizarre comme ça), mais la plupart des graines sera très bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X