Générateurs à congruence linéaire (GCL)

Il s'agit de l'algorithme le plus utilisé pour produire des nombres aléatoires depuis qu'il a été inventé en 1948 par D. H. Lehmer. C'est la suite :

xn+1 = (a·xn + c) mod m

avec a (multiplicateur), c (incrément), x0 (germe), et m qui sont quatre nombres entiers non-négatifs.

Dans tous les cas, les nombres de la suite sont compris entre 0 et m-1.


Expérience

Utilisez le programme javascript ci-dessous pour vous familiariser avec un générateur à conguence linéaire. Entrez le germe, a, c et le modulo m de la séquence pseudo-aléatoire.

Essayez les valeurs suivantes et commentez:

Germe a c m
12 25 16 256
11 25 16 256
10 25 16 256
0 31415821 1 100000000

La formule est simple mais le choix des trois paramètres a, c et m ne doit pas être fait à la légère, comme on le verra ci-dessous.



Germe :

a :

c :

Modulo :

Longueur :


Séquence pseudo-aléatoire


Critères de Knuth

Si on choisi c non nul, il est toujours possible d'obtenir une période de longueur m (donc pas de risque de blocage puisqu'on va retrouver tous les nombres entre 0 et m-1 dans la suite). D. Knuth fait la démonstration des critères que doivent remplir a, c et m pour cela :
  1. c et m doivent être premiers entre eux
  2. a-1 doit être un multiple de p, pour tout p nombre premier diviseur de m
  3. a-1 doit être un multiple de 4 si m est un multiple de 4.
  4. si m est une puissance de 2, le bit de poids faible des nombres produits vaut alternativement 0 et 1 (ce n'est d'ailleurs pas le seul cas où cela se produit).

Si c=0, la situation est plus compliquée parce qu'il reste toujours la possibilité de blocage (si x0=0), donc la période du générateur ne peut être au mieux que m-1. L'analyse dans le cas général est assez difficile, pour m = 2n avec n > 3 on peut dire que:

  • a mod 8 doit être égal à 3 ou 5
  • la période du générateur est 2(n-2) et tous les bits de poids faible des nombres produits sont identiques (il faut donc décaler le nombre produit de 1 vers la droite).

Pour ne pas retrouver les défauts graves de notre petit exemple, il faut regarder cette suite d'un peu plus près. Pour notre second essai, soyons plus prudents et respectons scrupuleusement les critères précédents:

xn+1 = (31'415'821xn + 1) mod 100'000'000     (citée par R. Sedgewick)

On a bien respecté les critères de Knuth :

  1. 1 et 100'000'000 sont bien premiers entre eux. Par conséquent, on est certain qu'il n'y aura pas de problème de blocage ou de série de nombres tous pairs ou impairs. Tous les nombres entre 0 et 99'999'999 vont sortir et chacun une fois tous les 100'000'000 de tirages.
  2. 31'415'821 - 1 = 31'415'820 est bien un multiple de 2 et de 5 (les deux seuls nombres premiers qui divisent 100'000'000).
  3. C'est aussi un multiple de 4 (car 100 000 000 est lui-même un multiple de 4).
Regardons ce que ça donne, par exemple pour x0 = 0. Les nombres produits sont:

1, 31415822, 40519863, 62952524, 25482205, 90965306, 70506227, 6817368, 12779129, 29199910, 45776111, 9252132, 22780373, 20481234, 81203115, ....

Vous ne remarquez rien ? Non? Alors surlignez la fin de cette ligne: Regardez le dernier chiffre.

Avoir la certitude que tous les nombres vont sortir ne suffit pas à garantir qu'ils seront suffisament aléatoires!

Quelques mauvais générateurs

Dans un article fameux, Park & Miller passent en revue de nombreux générateurs couramment utilisés et qui la plupart du temps présentent des défauts souvent assez graves. Citons en vrac:

xn+1 = 65'539 xn mod 231
(RANDU, implanté sur les IBM System/370)

xn+1 = (129 xn + 907'633'385) mod 232
(Le générateur de Turbo Pascal [cf. Knuth p.23])

xn+1 = (1'103'515'245 xn + 12'345) mod 231
(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)

Laissons la conclusion de tout ceci à Robert Sedgewick: «C'est une règle générale, les générateurs de nombres aléatoires sont délicats et doivent être traités avec respect. Il est difficile d'être certain qu'un générateur donné est bon sans investir d'énormes efforts dans des tests statistiques variés...».

Quelques bons générateurs

Afin d'éviter que n'importe qui propose un générateur pseudo-aléatoire sans savoir très bien ce qu'il fait (comme dans les exemples dramatiques précédents), Park & Miller ont proposé un générateur standard convenablement testé et dont le code est portable sur toutes les machines. Ils l'ont appelé le Standard minimal. Il est défini par:

xn+1 = 16'807 xn mod (231- 1)

D. 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 :

xn+1 = (137 xn + 187) mod 28
(mais une suite cyclique de 256 nombres, est-ce encore du hasard ?)

xn+1 = (1'664'525 xn + 1'013'904'223) mod 232
(générateur de Knuth & Lewis)

xn+1 = 69'069 xn mod 232
(générateur de Marsaglia au multiplicande remarquable, utilisé sur le VAX)

xn+1 = (31'167'285 xn + 1) mod 248
(générateur de Lavaux & Jenssens)

xn+1 = (6'364'136'223'846'793'005 xn + 1) mod 264
(générateur de Haynes)


Exercice

Programmez dans Mathematica les générateurs suivants:
  • Standard minimal: xn+1 = 16807 xn mod (231- 1)
  • RANDU: xn+1 = 65539 xn mod 231
Fonctions Mathematica utiles: AppendTo, For, Last, Mod, Module, N.

Vous produirez avec chacun de ces générateurs une liste de 100 nombres pseudo-aléatoires compris dans l'intervalle [0,1[.

Le fichier Mathematica complet est disponible, mais seulement pour les visiteurs autorisés!
Mot de passe :


Références


Didier Müller, 2.1.03