Il n’y a pas de hasard dans les générateurs algorithmiques de nombres dits pseudo-aléatoires. Comme tout programme informatique, quand on fournit les mêmes entrées au générateur, il produira les mêmes sorties, puisqu'il s'agit de machines de Turing déterministes. Ces paramètres en entrée s'appellent la graine ou le germe, et ces générateurs sont souvent basés sur des suites récurrentes : relancer deux fois de suite avec le même germe produit deux fois de suites la même séquence "pseudo-aléatoire".
Il y a donc reproductibilité chez les générateurs de nombres pseudo-aléatoires, et ces derniers sont appelés ainsi car, quoique déterministes, ce qu'ils produisent ressemble à de l'aléa. Plus précisément :
Au besoin, on peut accéder à des générateurs de nombres réellement aléatoires, au moins sur certains systèmes, comme suit :
>>> SystemRandom().random()
Cette fois-ci, Python ne va pas utiliser un algorithme de type suite récurrente, mais va mixer des données captées (température du processeur, etc.) à diverses autres données "aléatoires", telles que le résidu mémoire, la position de la souris, etc.
Programmez le chiffrement dit du masque jetable, présenté ci-dessus.
Une suite pseudo-aléatoire est une suite de nombres entiers $x_0$, $x_1$, $x_2$, etc. prenant ses valeurs dans l’ensemble {0, 1, 2, ..., m-1}.
Le plus souvent, chaque terme est le résultat d’un calcul sur le (ou les) terme(s) précédent(s). Il s'agit donc, comme on l'a évoqué, de suites récurrentes.
Le premier terme $x_0$ est appelé le germe de la suite.
Dans le cas où chaque terme de celle-ci n’est déterminé qu’à l’aide de son prédécesseur, la seule donnée du germe fixe logiquement la totalité de la suite. En d'autres termes, fournir deux fois de suite le même germe (avec la fonction seed de random) conduit à deux fois de suite l'obtention des mêmes nombres "pseudo-aléatoires" :
>>> from random import random, seed >>> for k in range(5): ... seed(0) ... for l in range(5): ... print random(), ... print ... 0.844421851525 0.75795440294 0.420571580831 0.258916750293 0.511274721369 0.844421851525 0.75795440294 0.420571580831 0.258916750293 0.511274721369 0.844421851525 0.75795440294 0.420571580831 0.258916750293 0.511274721369 0.844421851525 0.75795440294 0.420571580831 0.258916750293 0.511274721369 0.844421851525 0.75795440294 0.420571580831 0.258916750293 0.511274721369
De plus, dans ce cas, on rencontre forcément parmi les m+1 premiers termes deux valeurs égales... et alors les termes se répètent indéfiniment à l’identique (on est bien loin du hasard.)
Pour que ce phénomène gênant ne se fasse pas trop sentir, on prend en pratique des valeurs de $m$ très élevées ($m = 10^7$ pour excel.)
Si le germe est toujours le même, on retombe invariablement sur la même suite.
Pour cette raison, les générateurs de nombres aléatoires introduisent un soupçon de hasard « authentique » dans le choix du germe (en prenant, par exemple, les décimales de l’heure d’exécution du programme.)
On a par exemple utilisé m = 2147483647 et, après avoir choisi un germe x, e.g. en utilisant l’horloge système :
>>> from time import time >>> x = int(100*time()) >>> print x
on calculait le reste de $16807x$ (multiplication de 16807 par $x$) dans la division par $m$, pour obtenir le terme suivant. En d'autres termes, $x_0$ est le germe, et $x_{n+1}= 16807 x_n % m$.
Cette suite passe avec succès bon nombre de tests statistiques. Cependant, avec cette méthode :
Générez la suite de nombres pseudo-aléatoires proposée ci-dessus.
On a déjà expliqué la différence entre générateurs de nombres pseudo-aléatoires et source d'aléa physique (bruit matériel), et l'on a donné un premier exemple, désuet, de tels générateurs pseudo-aléatoires. Nous présentons dans ce qui suit quelques générateurs réellement utilisés, en commençant par les générateurs congruentiels linéaires.
Ces derniers sont définis ainsi : $X_{n+1} = ( a \cdot X_n + c ) \% m$, où $a$, $c$ et $m$ sont les paramètres du générateur.
Ces générateurs sont évidemment périodiques, et certains paramètres produisent de meilleures suites que d'autres, dans le sens où leurs périodes sont maximales. Pour obtenir de tels paramètres, il faut et il suffit que:
(valable pour $c\neq 0$).
On choisit ordinairement pour $m$ une puissance de 2, et les conditions ci-dessus se simplifient alors grandement. La première condition, par exemple, devient "$c$ impair".
Ce générateur a été proposé il y a peu par Marsaglia, il possède à la base trois paramètres entiers $a,b,c$. On peut résumer son fonctionnement de la manière suivante:
Un bout de code en C détaillant le XORshift avec (12, 25, 27) comme paramètres serait donc :
x ^= x >> 12; // a x ^= x << 25; // b x ^= x >> 27; // c
Si le sujet vous intéresse, vous pourrez programmer, puis tester, les générateurs suivants :