La majorité des compilateurs C viennent avec une collection de bibliothèques
normalisées standard contenant les opérations courantes (affichage,
calculs mathématiques, lecture et écriture dans des fichiers ...). Ces bibliothèques
contiennent principalement des fonctions qui sont utilisables en incluant l'entête
de la bibliothèque concernée. Par exemple, pour utiliser la fonction printf()
, il
faut inclure la bibliothèque stdio.h
:
#include <stdio.h>
La bibliothèque sdtlib.h
contient diverses fonctions de base (allocation mémoire,
conversion de variables ...). Les fonctions qui vont nous intéresser ici sont les
fonctions srand()
et rand()
qui permettent de générer des nombres aléatoires (ou
plus exactement des nombres pseudo-aléatoires, mais nous y reviendrons).
Nous allons nous intéresser aux éléments suivants de la bibliothèque stdlib.h
:
// Constante symbolique
#define RAND_MAX
// Fonctions
int rand(void);
void srand(unsigned int seed);
La fonction rand()
génére un nombre pseudo-aléatoire compris entre 0 et RAND_MAX
.
RAND_MAX
est une constante symbolique (ou macro) définie dans stdlib.h
. Cette
constante contient la valeur maximale retournée par la fonction rand()
.
Voici un exemple élémentaire :
// Affiche la valeur max du générateur pseudo-aléatoire
printf ("Valeur max : %d\n", RAND_MAX);
// Tire deux nombres aléatoires
printf ("Un nombre aléatoire : %d\n", rand());
printf ("Un autre nombre aléatoire : %d\n", rand());
Si vous exécutez le code ci-dessus plusieurs fois, vous vous apercevrez qu'il tire toujours les mêmes nombres.
Un processeur est une machine deterministe qui ne peut pas générer de véritables
nombres aléatoires, d'ailleurs la notion générale d'aléatoire reste discutable. Les
nombres générés par la fonction rand()
sont des nombres pseudo-aléatoires
Un algorithme pseudo-aléatoire génére une séquence de nombres qui présentent certaines propriétés du
hasard, comme par exemple l'équiprobabilité. Si le programme précédent tire toujours
les mêmes nombres, c'est parce que ce sont les premiers de la séquence. La fonction
srand()
pour seed random (graine de l'aléatoire) permet de définir la graine
du générateur et ainsi modifier le point initial de la séquence. Pour éviter
d'obtenir toujours les mêmes nombres aléatoires, on utilise classiquement l'heure
courante comme graine du générateur :
#include <stdlib.h>
#include <time.h>
// Initialise le générateur pseudo-aléatoire
srand(time(NULL));
Maintenant, à chaque exécution (au moins séparée d'une seconde de la précédente) le programme affiche des nombres différents.
Il est classique de vouloir tirer des nombres dans un intervalle donné. Si l'on souhaite
tirer un nombre entre 0 et max
, la meilleure solution est d'utiliser le reste de la
division entière (modulo %
) :
// x est un nombre pseudo-aléatoire entre 0 et max inclus
int x = rand() % (max+1);
Si l'on souhaite une borne inférieure, il faut décaler le tirage en ajoutant la borne inférieur :
// x est un nombre pseudo-aléatoire entre min et max inclus
int x = min + rand() % (max + 1 - min);
Il est également fréquent de devoir tirer un nombre réel. L'astuce consiste à
diviser le nombre généré par RAND_MAX
, et ainsi obtenir un
résultat entre 0 et 1 :
// x est un nombre pseudo aléatoire compris entre 0 et 1
float x = (float)rand()/(float)(RAND_MAX);
Notons le changement de type (cast int
-> float
) afin de réaliser la division sur des
flottants. En divisant RAND_MAX
par la borne max
, on peut obtenir le
tirage d'un nombre réel compris entre 0 et max
:
// x est un nombre pseudo aléatoire entre 0 et max
float x = (float)rand() / ((float)RAND_MAX/max);
Enfin, il suffit de décaler l'intervalle pour obtenir un nombre réel dans l'intervalle
[min
; max
] comme vu précédemment :
// x est un nombre pseudo aléatoire entre min et max
float x = min + (float)rand() / ((float)RAND_MAX/(max-min));
Écrire un programme qui simule le tirage de deux dés à 6 faces :
Dé 1 : 6 Dé 2 : 1
Pour évaluer les étudiants, un enseignant a besoin de 24 notes aléatoires dans l'intervalle [0;20]. Écrire un programme qui génère ces 24 notes :
Note n°1 : 9.2 Note n°2 : 13.1 Note n°3 : 1.1 Note n°4 : 13.2 ... Note n°21 : 17.5 Note n°22 : 18.4 Note n°23 : 19.7 Note n°24 : 15.7
Ecrire une fonction hasard(int a, int b)
qui tire un nombre entier au hasard dans l'intervalle [a
; b
].
Tirer et afficher 100 nombres au hasard entre 8 et 12 inclus :
8 9 8 11 9 9 12 12 8 8 8 12 12 11 10 11 12 10 11 11 8 11 10 11 10 9 8 10 10 10 12 10 8 9 8 9 10 10 8 12 10 10 9 9 8 11 10 10 10 10 8 10 8 8 11 12 11 8 11 8 12 10 11 12 8 11 8 12 10 10 12 10 8 8 11 10 8 10 9 11 12 10 10 9 12 10 9 10 11 12 11 10 12 9 10 9 9 10 9 12
Ecrire une fonction `randFloat()`` qui tire un nombre pseudo-aléatoire entre 0 et 1. Tirer un million de nombres et afficher la moyenne. La moyenne doit se situer proche de 0.5 :
Moyenne = 0.5003
Les librairies standard sont-elles fournies avec tous les compilateur C ?
Les bibliothèques standard du C sont-elles compatibles d'un compilateur à l'autre ?
Que fait un générateur pseudo-aléatoire ?
À quoi sert cette ligne de code ?
srand(time(NULL));
Que fait le code suivant ?
x = 5 + rand()%10;