70 votes

Méthode recommandée pour initialiser srand ?

J'ai besoin d'une "bonne" façon d'initialiser le générateur de nombres pseudo-aléatoires en C++. J'ai trouvé un article qui déclare :

Afin de générer des nombres de type aléatoire srand est généralement initialisé à une certaine valeur distinctive, comme celles liées au temps d'exécution. Pour exemple, la valeur renvoyée par la fonction fonction time (déclarée dans l'en-tête ctime) est différente à chaque seconde, ce qui est suffisamment distincte pour la plupart besoins aléatoires.

Unixtime n'est pas assez distinctif pour mon application. Quelle est la meilleure façon de l'initialiser ? Les points bonus si c'est portable, mais le code sera principalement exécuté sur des hôtes Linux.

Je pensais faire des calculs de pid/unixtime pour obtenir un int, ou éventuellement lire les données à partir de /dev/urandom .

Merci !

EDIT

Oui, je lance mon application plusieurs fois par seconde et j'ai rencontré des collisions.

67voto

Jonathan Wright Points 3146

C'est ce que j'ai utilisé pour les petits programmes en ligne de commande qui peuvent être exécutés fréquemment (plusieurs fois par seconde) :

unsigned long seed = mix(clock(), time(NULL), getpid());

Où se trouve le mélange :

// http://www.concentric.net/~Ttwang/tech/inthash.htm
unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
{
    a=a-b;  a=a-c;  a=a^(c >> 13);
    b=b-c;  b=b-a;  b=b^(a << 8);
    c=c-a;  c=c-b;  c=c^(b >> 13);
    a=a-b;  a=a-c;  a=a^(c >> 12);
    b=b-c;  b=b-a;  b=b^(a << 16);
    c=c-a;  c=c-b;  c=c^(b >> 5);
    a=a-b;  a=a-c;  a=a^(c >> 3);
    b=b-c;  b=b-a;  b=b^(a << 10);
    c=c-a;  c=c-b;  c=c^(b >> 15);
    return c;
}

61voto

Loki Astari Points 116129

La meilleure réponse est d'utiliser le numéro de randum de Boost.

Mais si nous parlons de rand() et srand()
Le meilleur moyen est d'utiliser time().

int main()
{
    srand(time(NULL));

    ...
}

À chaque démarrage, time() renvoie une valeur unique (sauf si vous lancez l'application plusieurs fois par seconde). Dans les systèmes 32 bits, elle ne se répétera que tous les 60 ans environ.

Je sais que vous pensez que le temps n'est pas assez unique mais j'ai du mal à le croire. Mais je suis connu pour avoir tort.

Si vous lancez un grand nombre de copies de votre application simultanément, vous pouvez utiliser une minuterie avec une résolution plus fine. Mais vous courrez alors le risque d'une période de temps plus courte avant que la valeur ne se répète.

OK, donc si vous pensez vraiment que vous lancez plusieurs applications par seconde.
Utilisez ensuite un grain plus fin sur la minuterie.

 int main()
 {
     struct timeval time; 
     gettimeofday(&time,NULL);

     // microsecond has 1 000 000
     // Assuming you did not need quite that accuracy
     // Also do not assume the system clock has that accuracy.
     srand((time.tv_sec * 1000) + (time.tv_usec / 1000));

     // The trouble here is that the seed will repeat every
     // 24 days or so.

     // If you use 100 (rather than 1000) the seed repeats every 248 days.

     // Do not make the MISTAKE of using just the tv_usec
     // This will mean your seed repeats every second.
 }

16voto

Evan Teran Points 42370

Si vous avez besoin d'un meilleur générateur de nombres aléatoires, n'utilisez pas la libc rand. Utilisez plutôt quelque chose comme /dev/random ou /dev/urandom directement (lire dans un int directement à partir de celui-ci ou quelque chose comme ça).

Le seul avantage réel de la libc rand est que, étant donné une graine, elle est prévisible, ce qui facilite le débogage.

13voto

shoosh Points 34322

Sous Windows :

srand(GetTickCount());

fournit une meilleure semence que time() puisque c'est en millisecondes.

7voto

user39307 Points 584

La meilleure solution est d'utiliser un autre générateur de nombres pseudo-aléatoires. Le twister de Mersenne (et le Wichmann-Hill) est ma recommandation.

http://en.wikipedia.org/wiki/Mersenne_twister

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