Les fonctions aléatoires en C++ 11

 

 

 

 

 

La librairie standard a été étoffée avec l’arrivée de la version 11 du C++. Pour la gestion des fonctions aléatoires, nous avons aujourd’hui à disposition une bibliothèque assez complète qui suit bien mieux les standards C++  que le bon vieux rand(). Dans cet article, je vous présente sans prétention les alternatives à rand() et consort, telles qu’elles devraient être implémentées. Si votre compilateur ou environnement ne supporte pas C++11 complètement, et c’est tout à fait possible, les codes suivants ne compileront pas.

 

Un tirage aléatoire avec rand()

 

 

 

Pour utiliser rand(), il faut disposer de la bibliothèque cstdlib : #include <cstdlib>

 

 

Pour un résultat :

 

 

Nous remarquons tout d’abord que les tirages aléatoires sont toujours les mêmes. Ensuite que nous n’avons pas borné le tirage.

 

Pour obtenir des tirages qui sont différents à chaque lancement, il faut initialiser la série aléatoire :

 

 

L’utilisation de time ici permet d’initialiser la série avec une graine qui dépend du temps, donc variable avec les exécutions. Ne pas oublier l’include #include <ctime>.  Le transtypage n’est nécessaire que pour faire taire le compilateur qui se plaint sur les types unsigned int et time_t. Le type time_t est sur mon compilateur compatible avec unsigned int, mais ce n’est pas garanti par la norme.

 

Enfin, pour obtenir des valeurs entre 1 et 6 (comme pour un dé classique), je rajoute le code suivant :

 

 

Les valeurs vont de 1  à 6 inclus. Le tirage n’est pas excellent en terme d’aléatoire, il serait sans doute meilleur d’utiliser RAND_MAX pour calculer la valeur entre 1 et 6.

 

Un tirage aléatoire avec la bibliothèque random

 

 

 

Utilisant la dernière version de C++, vous pouvez mettre en œuvre la biliothèque random.

 

En utlisant #include <random>, vous accédez aux classes de cette bibliothèque.

 

Il y a essentiellement 2 catégories de classes indispensables : les moteurs de génération aléatoire et les distributions. Le moteur de génération, comme son nom l’indique, produit des séries de nombres pseudo-aléatoires (utilisant une graine à fournir), et les distributions accommodent ces séries suivant les lois classiques : uniformes, de Bernoulli, de Poisson ou normales.

 

Le choix du moteur de génération se fait en fonction de considérations de rapidité et d’occupation mémoire. Les algorithmes proposés par la norme sont : linear_congruential_engine, mersenne_twister_engine et subtract_with_carry_engine. Ces classes sont des template, donc paramétrables. Il y a aussi des adaptateurs de moteur de génération, qui utilisent les moteurs décrits ci-dessus, mais qui altèrent certaines caractéristiques.

 

Enfin, des générateurs classiques, basés sur les moteurs ci-dessus, sont proposés. Ce sont ces moteurs là que la plupart d’entre nous vont utiliser. Pour la définition exacte des algorithmes utilisés, je vous laisse vous reporter à la documentation : minstd_rand0, minstd_rand, mt19937, mt19937_64, ranlux24_base, ranlux48_base, ranlux24, ranlux48, knuth_b et default_random_engine. Ce dernier est dépendant de l’implémentation de votre bibliothèque.

 

Pour faire un tirage, il faut choisir un moteur (ou bien paramétrer le vôtre) et choisir une distribution. Le code suivant permet par exemple un tirage entre 1 et 6, suivant une distribution équiprobable entre ces bornes.

 

 

Nous retrouvons dans le cas le même problème d’initialisation de la série aléatoire que précédemment avec rand(). Pour initialiser la série, il faut fournir un paramètre au moteur de génération. Par exemple le temps.

 

 

Si vous voulez le faire avec la bibliothèque chrono (standard C++11), voici le code à écrire, en n’oubliant pas l’include :  #include<chrono>

 

 

Enfin, pour simplifier les tirages, on peut utiliser bind (standard). Voici le code à écrire, ne pas oublier l’include #include <functional>. Ce code n’apporte rien au tirage lui-même, mais peut vous simplifier la vie pour les appels.

 

 

Finissons avec une implémentation d’une classe Dé à 6 faces.

 

 

 

 

Faites rouler le dé et vous obtenez un tirage aléatoire ;)

 

Conclusion

 

 

 

D’un façon générale, la bibliothèque random du C++11 est bien meilleure en terme d’aléatoire que la bonne vieille fonction rand(). Mais elle propose surtout beaucoup plus de possibilités de paramétrage. En utilisant ce qui est déjà configuré en terme de moteur et de distribution, vous avez de quoi couvrir pas mal de besoins. Il est conseillé, sauf si vous avez réellement des besoins spécifiques, d’utiliser le moteur pas défaut.