Problèmes liés à l'ensemencement d'un générateur de nombres pseudo-aléatoires plus d'une fois?

StackOverflow https://stackoverflow.com/questions/976993

Question

Je l'ai vu quelques recommandations pour ne pas l'ensemencement des générateurs de nombres pseudo-aléatoires plus d'une fois par l'exécution, mais jamais accompagné d'une explication approfondie. Bien sûr, il est facile de voir pourquoi l'exemple suivant (C / C ++) n'est pas une bonne idée:

int get_rand() {
  srand(time(NULL));
  return rand();
}

depuis l'appel get_rand plusieurs fois par seconde produit des résultats répétés.

Mais ne l'exemple suivant encore une solution acceptable?

MyRand.h

#ifndef MY_RAND_H
#define MY_RAND_H

class MyRand
{
  public:
    MyRand();
    int get_rand() const;
  private:
    static unsigned int seed_base;
};

#endif

MyRand.cpp

#include <ctime>
#include <cstdlib>
#include "MyRand.h"

unsigned int MyRand::seed_base = static_cast<unsigned int>(time(NULL));

MyRand::MyRand()
{
  srand(seed_base++);
}

int MyRand::get_rand() const
{
  return rand();
}

main.cpp

#include <iostream>
#include "MyRand.h"

int main(int argc, char *argv[]) 
{
  for (int i = 0; i < 100; i++) 
  {
    MyRand r;
    std::cout << r.get_rand() << " ";
  }
}

i.e.. même si MyRand: constructeur de s est appelé plusieurs fois en succession rapide, chaque appel à srand a un autre paramètre. Évidemment, c'est pas thread-safe, mais là encore n'est rand.

Était-ce utile?

La solution

Chaque fois que vous appelez un numéro pseudo-aléatoire fonction de générateur, le générateur prend un certain état interne et produit un nombre pseudo-aléatoire et un nouvel état interne. L'algorithme de transformation de l'état interne est soigneusement choisie de façon aléatoire la sortie apparaît.

Lorsque vous semez le générateur de nombres aléatoires, vous définissez essentiellement cet état interne. Si vous rétablissez l'état interne à une valeur prévisible, vous perdrez l'apparition de l'aléatoire.

Par exemple, un RNG simple, populaire, est un générateur de congruence linéaire. Les chiffres sont générés comme ceci:

X[n+1] = (a X[n] + c) mod m

Dans ce cas, X [n + 1] est à la fois le résultat et le nouvel état interne. Si vous semez le générateur chaque fois que vous suggérez ci-dessus, vous obtiendrez une séquence qui ressemble à ceci:

{(ab + c) mod m, (a(b+1) + c) mod m, (a(b+2) + c) mod m, ...}

où b est votre seed_base. Cela ne semble pas du tout hasard.

Autres conseils

Si votre semence est prévisible, ce qui est ici depuis que vous êtes juste incrémenter, la sortie de rand () sera également prévisible.

Cela dépend vraiment pourquoi vous voulez générer des nombres aléatoires, et comment « au hasard » est un hasard pour vous acceptable. Dans votre exemple, il peut éviter les doublons dans une succession rapide, et qui peut être assez bon pour vous. Après tout, ce qui importe est qu'il fonctionne.

Sur presque toutes les plateformes il y a une meilleure façon de générer des nombres aléatoires que rand ().

Eh bien, il est un traitement supplémentaire qui n'a pas besoin d'être fait.

Dans ce scénario que je venais appeler le constructeur une fois avec une graine en fonction du temps avant le début de la boucle. Cela garantira des résultats aléatoires sans charge supplémentaire de changer les graines pour chaque itération.

Je pense pas que votre méthode est une plus au hasard que cela.

Vous pouvez penser de la génération de nombres aléatoires (ce n'est pas strictement vrai plus sage implémentation, mais sert d'illustration) comme une table de valeurs. Si vous vous souvenez de faire tout ce genre de choses dans les statistiques pour faire de simples échantillons aléatoires, une graine vous dit essentiellement ce que la ligne et de la colonne pour commencer à votre grande table de nombres aléatoires. Réensemencement encore et encore est tout simplement inutile puisque nous pouvons déjà supposer que les chiffres sont normalement distribués déjà.

Il n'y a simplement aucun avantage supplémentaire à l'ensemencement plus d'une fois car cela devrait être assez bon (selon l'application). Si vous avez besoin « plus » nombres aléatoires, il existe de nombreuses méthodes de génération de nombres aléatoires. Un cas que je peux penser est de générer des nombres aléatoires d'une manière thread-safe.

Bien que votre solution est acceptable, vos numéros ne sera plus aléatoire que l'ensemencement une fois, à l'échelle mondiale. srand ne devrait généralement pas appartenir à un constructeur. Si vous souhaitez soutenir des nombres aléatoires, des semences une fois quand le programme démarre, et oublier.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top