Générateur congruentiel linéaire
Un générateur congruentiel linéaire est un générateur de nombres pseudo-aléatoires dont l'algorithme, introduit en 1948 par Derrick Lehmer, sous une forme réduite, pour produire des nombres aléatoires, est basé sur des congruences et une fonction affine.
Définition
Les nombres pseudo aléatoires forment une suite dont chaque terme dépend du précédent, selon la formule :
où a est le multiplicateur, c l'incrément et m le module.
Le terme initial est appelé la graine (seed en anglais). C'est elle qui va permettre de générer une suite apparemment aléatoire. Pour chaque graine, on aura une nouvelle suite. Cependant, il est possible que certaines graines permettent d'obtenir une suite plus aléatoire que d'autres.
Du fait de l'opération mod (reste dans la division euclidienne de par m), les termes de cette suite sont compris entre 0 et . De plus, comme chaque terme dépend entièrement du précédent, si un nombre apparaît une deuxième fois, toute la suite se reproduit à partir de ce nombre. Or le nombre de valeurs que le nombre peut prendre étant fini (égal à m), la suite est amenée à se répéter au bout d'un certain temps. On dit qu'elle est ultimement périodique.
Du bon choix des paramètres a, c et m
Dans ce type d'algorithme, la qualité du générateur va entièrement dépendre du choix de a, c et m car on ne peut pas se satisfaire d'un générateur qui produit des suites plus ou moins aléatoires, sans aucune raison apparente, selon le choix de X0.
Un mauvais exemple
Choisir les valeurs a, c et m « au hasard » n'est pas une bonne idée. Prenons un exemple, soit le générateur congruentiel linéaire employant les valeurs a = 25, c = 16, m = 256, nous obtenons :
- avec X0 = 125, la suite : 125, 69, 205, 21, 29, 229, 109, 181, 189, 133, 13, 85, 93, 37, 173, 245, 253, 197, 77, 149, ...
- avec X0 = 96, la suite : 96, 112, 0, 16, 160, 176, 64, 80, 224, 240, 128, 144, 32, 48, 192, 208, 96, 112, 0, 16, ...,
- avec X0 = 50, la suite : 50, 242, 178, 114, 50, 242, 178, 114, 50, 242, ...
- avec X0 = 10, la suite : 10, 10, 10, 10, ...
Il est clair que ces suites ne peuvent être considérées comme aléatoires.
On voit donc bien que l'on doit choisir avec précaution les paramètres du générateur si l'on espère obtenir des nombres qui s'approchent de l'aléa parfait. Il faut alors se demander comment choisir a, c et m convenablement.
Choix du module
Les générateurs congruentiels font intervenir un calcul modulo m, et donc a priori une division euclidienne, ce qui peut avoir un coût de calcul important dans le cadre d'une utilisation fréquente du générateur. La solution la plus simple est d'utiliser un module de type m = 2e. En effet, les ordinateurs calculant naturellement en base binaire, un tel choix est tout à fait transparent pour eux, ce qui rend inutile une division euclidienne.
Toutefois, ce choix présente une limite importante : les bits dits de poids faible (les bits les plus à droite) sont beaucoup moins aléatoires que ceux de la partie de poids fort (les bits les plus à gauche). En effet, si d est un diviseur de m, alors la suite Yn, telle que :
satisfait à la suite congruentielle linéaire :
en particulier, avec d = 2k, pour k fixé, compris entre 1 et e, on voit que les k chiffres de poids faible, ont une période maximale de 2k, évidemment inférieure à m.
Pour remédier à ce problème, on peut ne garder que les bits de poids fort, c'est-à-dire garder les bits les plus à gauche du nombre obtenu. Si l'on tronque les k derniers bits, on aura alors un générateur pseudo aléatoire de nombres compris entre 0 et .
Une autre solution consiste à prendre un module du type , ce qui permet encore d'éviter une division euclidienne par une astuce (cf. The Art Of Computer Programming de D. E. Knuth).
Choix du multiplicateur et de l'incrément
Afin de pouvoir choisir une graine sans contraintes entre et , il faut chercher à maximiser la période du générateur. Or il se trouve que les valeurs de et sont connues, ce qui permet d'obtenir une période maximale (égale à ).
Si la période d’un générateur congruentiel linéaire est maximale si et seulement si :
- est premier avec . .
- Pour chaque nombre premier divisant , est un multiple de .
- est un multiple de 4 si en est un.
On remarquera que l'on possède un théorème d'équivalence (si et seulement si) : la période est maximale pour toutes les valeurs qui possèdent les propriétés du théorème et seulement pour celles-là.
On possède, de plus, de conditions suffisantes dans le cas particulier où c est nul. Ainsi, pour c nul la période d'un générateur congruentiel linéaire est maximale si :
- est premier.
- est un multiple de .
- n'est pas divisible par , pour
Attention: ce n'est pas une équivalence !
Le potentiel
Le potentiel est une notion qui permet d'écarter certains générateurs insuffisamment aléatoires. Il est toujours défini que pour une suite possédant une période maximale (et ce, d'après la deuxième propriété énoncée plus haut). On ne peut pas toujours le définir sur les autres générateurs, et il existe de bons générateurs sur lesquels le potentiel n'est pas défini.
Le potentiel d’une suite possédant une période maximale est défini comme le plus petit entier tel que :
Pour une suite de période maximale, on peut prendre , et donc :
ainsi, avec :
et un potentiel inférieur ou égal à trois, apparaît immédiatement comme trop faible car la suite n’est pas suffisamment aléatoire. En fait un potentiel de 5 ou plus est conseillé.
Rappelons cependant que la notion de potentiel est uniquement là pour écarter quelques mauvais générateurs. Un générateur possédant un potentiel supérieur à 5 ne peut en aucun cas être d’emblée considéré comme bon, il doit d’abord subir quelques tests.
Tests statistiques
![](http://upload.wikimedia.org/wikipedia/commons/thumb/a/a3/Lcg_3d.gif/220px-Lcg_3d.gif)
Comme tous les générateurs de nombres pseudo-aléatoires, le générateur congruentiel linéaire doit être soumis à une série de tests avant d’être homologué.
Le plus connu d’entre eux, le test de fréquence n'est généralement pas un problème pour un générateur congruentiel linéaire de période maximale, mais il existe bien d'autres tests : Test des séries, Gap test, Run test, ... ;
l'un des plus discriminant, car aucun générateur congruentiel linéaire démontré mauvais ne l’a réussi, est le Test spectral.
Exemples
Algorithme | a | c | m | Remarques |
---|---|---|---|---|
RANDU | 65539 | 0 | 231 | Biaisé et fortement déconseillé |
générateur de Robert Sedgewick | 31415821 | 1 | 108 | Intéressant mais déconseillé (essayer avec ) |
Standard minimal | 16807 | 0 | 231-1 |
- RANDU défini par . Implanté sur les IBM System/370 et réputé mauvais par tous ceux qui ont à l'utiliser sérieusement[réf. souhaitée].
- Le générateur de Turbo Pascal défini par . On sait dans 1 cas sur 129 que , ce qui est un biais énorme pour une application scientifique. En plus comme 129 est de la forme 2^n + 1, les nombres produits ne sont pas si « aléatoires que ça » [cf. Knuth p.23].
- Le générateur d'UNIX (dont le comité ANSI C a heureusement recommandé de ne conserver que les 16 bits de poids fort) :
. Même la documentation du Berkeley 4.2 admet que les bits de poids faible des nombres produits ne sont pas vraiment aléatoires.
Autres exemples
Knuth recense dans « Seminumerical Algorithms » un certain nombre de générateurs congruentiels linéaires de qualité. S'il n'est pas possible d'utiliser le Standard Minimal, on pourra essayer par exemple :
- (une suite cyclique de 256 nombres, est-ce encore du hasard ?)
- : générateur de Knuth & Lewis
- : générateur de Marsaglia au multiplicande remarquable, utilisé sur le VAX
- : générateur de Lavaux & Jenssens
- : générateur de Haynes
Dans tous ces cas, comme le modulant est une puissance de 2, les bits de poids faible des nombres produits ne sont pas eux très « aléatoires ». Il est par conséquent préférable de ne conserver que les poids forts (16 bits par exemple), comme le fait le générateur de Borland C++ par exemple :
- et on sort
Ce faisant, la période du générateur reste la même mais on ne va produire que des nombres compris entre 0 et 65535, chacun se retrouvant 32768 fois dans la suite.
Voir aussi
Bibliographie
(en) Donald E. Knuth, The Art of Computer Programming, vol. 2 : Seminumerical Algorithms, 3e éd., Addison-Wesley, Boston, 1998