Générer des nombres aléatoires efficacement avec rand()

Décembre 2016


Générer des nombres aléatoires efficacement avec rand()


Vous avez peut-être remarqué qu'en C, en utilisant la fonction rand() de la bibliothèque standard, vous obtenez des résultats décevants, trop souvent les mêmes.

Prenons un exemple, vous voulez générer 5 nombres aléatoires d'affilée:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    int i;
    for(i=0; i<5; i++)
    {
        printf("%d\n", rand());
    }
    return 0;
}


Exécutons ce programme et regardons ce qu'il nous écrit:
41
18467
6334
26500
19169


C'est bien, ce sont des résultats sensiblement différents. Mais si vous relancez votre programme, vous aurez la même série de nombres.

Pour modifier le comportement du générateur de nombres aléatoires, on peut modifier une variable sur laquelle il se base pour ses calculs. On appelle ça une graine (ou seed).
Cette graine se modifie avec la fonction srand():
srand(valeur de la graine)

Il faut un nombre que l'on ne peut pas prévoir facilement et qui varie toujours d'un instant à l'autre.
Par exemple, vous pouvez prendre le nombre de cycles utilisés par votre processeur depuis le démarrage.
Il peut être obtenu, sur les processeurs x86 (intel, Amd etc...), avec la commande assembleur rdtsc.
L'écriture d'une fonction rdtsc() appelant cette commande en assembleur pourra vous faciliter la vie, la syntaxe suivante fonctionne avec gcc sous Linux, que vous pouvez retrouver d'ailleurs avec dev C++ sous Windows.

#include <stdlib.h>
#include <stdio.h>

int rdtsc()
{
    __asm__ __volatile__("rdtsc");
}

int main()
{
    int i;
    for(i=0; i<5; i++)
    {
        srand(rdtsc());
        printf("%d\n", rand());
    }
    return 0;
}


Avec ce code, vous aurez déjà des nombres aléatoires plus efficaces.

Attention, cette solution ne fonctionne que sur les processeurs x86. Si votre programme doit être portable sur d'autres architectures de processeurs, il faudra envisager autre chose.

Evitez également d'activer des optimisations dans le compilateur (option -O1, -O2, -O3 etc...) ; si vous utilisez cette fonction rdtsc, vous risquez d'avoir un comportement étrange....

A voir également :

Ce document intitulé «  Générer des nombres aléatoires efficacement avec rand()  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.