Licence 1 MASS - Introduction à Java et l'algorithmique Sébastien Verel
verel@i3s.unice.fr www.i3s.unice.fr/∼verel
Équipe ScoBi - Université de Nice Sophia-Antipolis
05 mars 2012
Objectifs de la séance 6
Faire la diérence entre aléatoire et pseudo-aléatoire
Simuler un nombre pseudo-aléatoire entier ou ottant entre 2 bornes données
Ecrire un algorithme utilisant un générateur pseudo-aléatoire Ecrire un algorithme qui génère des séries temporelles du type ut+1 =aut+b+et ut+1 = (a+)ut+b
Question principale du jour :
Comment générer une série de nombres qui ont l'air d'être aléatoires ?
Plan
1 Introduction
2 Générateurs pseudo-aléatoire
3 Algorithmes stochastiques
Aiguille de Buon
Expérience
Lancer n fois une aiguille de longueur 2l sur parquet dont les lames sont de largeur 2a.
Soit pn le nombre de fois que l'aiguille intercepte une lame de parquet.
La fréquence pnn permet d'approximer le nombre π. limn→∞ pn
n = 2l aπ
→à partir d'événements aléatoires, il est possible d'approximer une valeur
Besoin de nombres aléatoires
Simulation :
Modèle économique, sociologique, physique, médicale, ...
Cryptographie :
Génération sûre de clés de chirement Optimisation stochastique :
méthodes de MonteCarlo, recuit simulé, algorithmes génétiques, Paritcules Swarm Optimisation...
Jeux de hasard : Loto, suduko, ...
Besoin croissant de nombres aléatoires en particulier en simulation et en cryptographie
Problème de génération
Méthodes principales de générateurs de nombres aléatoires : A l'aide d'un système physique dont l'état est aléatoire : Valeur précise d'une résistance, apparition des taches solaires, vibration de matière...
→ bonne méthode mais lente A l'aide d'un ordinateur :
Mais un ordinateur est une machine déterministe :
tout état prochain est une fonction (image unique) des états précèdents de la machine.
→ rapide, facile à utiliser dans un ordinateur
→ mais PAS aléatoire du tout...
Depuis peu : combinaison des deux
Technique de génération : le pseudo-aléatoire
2 étapes :
Initialisation d'un premier nombre appelégraine : u0
Génération d'une suite de nombres dénie par récurrence : un+1 =f(un)
3402093,56,125672,10048,678089, ...
Limite des machines : le pseudo-aléatoire
Mais :
Taille de mémoire limitée
Nombre de registres de calcul d'un processeur limité
→inévitable périodicitédes nombres générés pseudo-aléatoirement par ordinateur
La suite des nombres doit avoir certaines propriétés de l'aléatoire
→ générateur pseudo-aléatoire
Petit historique
Développement essentiellement dû au besoin en simulation et cryptographie.
1946 : John Von Neumann, générateur Middle square 1948 : D. H. Lehmer, générateur congruenciel
1958 : G.T. Mitchell, et D.P. Moore, améalioration 1997 : Makoto Matsumoto et Takuji Nishimura : Mersenne-Twister
Algorithme de Von Neumann
Middle Square
Principe : pour calculer le nombre suivant, on élève au carré le nombre précèdent puis on conserve les chires du milieu.
Exemple :
Graine : 1111
1. 11112=1234321, premier nombre : 23432
2. 234322 =549058624, deuxième nombre : 4905862 3. ...
Périodicité faible
Dépend beaucoup de la graine
à fonctionnner sur l'ENIAC, mais très vite limité.
Algorithme de Von Neumann
n : variable globale contenant le nombre courant pseudo-aléatoire Algorithme randSeed(k : entier) :
début n ← k n
Algorithme rand() : entier début
variable nbChires : entier nbChires ← E(log10(n2))
n ← modulo(n2, 10nbChrires) / 10 retourner n
n
Méthode de Von Neumann
// nombre courant pseud-aléatiore int n = 1111;
/********************************
* initialisation générateur pseudo-aléatoire de Von Neumann
** entrée :
* graine du générateur aléatoire
** sortie :
* aucune
*******************************/
void randSeed(int k) { n = k;
}
Méthode de Von Neumann
/********************************
* générateur pseudo-aléatoire de Von Neumann
** entrée :
* aucune
** sortie :
* nombre non attendu suivant
*******************************/
int rand() {
int nbChiffre = int(log(n * n) / log(10));
n = (n * n) % int(exp(nbChiffre * log(10))) / 10;
return n;
}
void setup() { randSeed(1111);
println(rand());
println(rand());
}
Méthode de Fibonacci
Basé sur la suite de Fibonacci et l'arithmétique modulaire.
xn= (xn−1+xn−2)mod M avec x0 et x1 comme graines
Ou une variante avec k un entier.
xn= (xn−1+xn−k) mod M avec x0... xk−1 comme graines
Qualité : dépend de k et des nombres utilisés pour graines Peu de consommation de ressources
Simple à implémenter....
Méthode de Fibonacci
Algorithme
On suppose n0, n1 et M sont des nombres entiers dénis de manière globale.
Algorithme rand() : entier début
variable suiv : entier
suiv ← modulo(n0+n1, M) n0 ←n1
n1 ←suiv retourner suiv n
Méthode Fibonacci
// nombres courants pseudo-aléatoires int n0 ;
int n1 ; // congruence int M = 1000;
/********************************
* générateur pseudo-aléatoire de Von Neumann
** entrée :
* graine du générateur aléatoire
** sortie :
* aucune
*******************************/
void randSeed(int _n0, int _n1) { n0 = _n0;
n1 = _n1;
}
Méthode Fibonacci
/********************************
* générateur pseudo-aléatoire Fibonacci
** entrée :
* aucune
** sortie :
* nombre non attendu suivant
*******************************/
int rand() {
int suiv = (n0 + n1) % M;
n0 = n1;
n1 = suiv;
return suiv;
}
void setup() { randSeed(23456, 9726);
println(rand());
println(rand());
}
Générateurs congruentiels linéaires
Basé sur les suites arithmétiquo-géométriques et l'arithmétique modulaire.
xn =axn−1+c mod m avec x0 une graine.
Période au maximum m.
m choisit de la taille des nombres en machine 232. Simple à implémenter....
Algorithme
On supposera que x0, a, c et m sont déterminés globalement, ainsi que le nombre courant x.
Algorithme rand() : entier début
x ← modulo(ax+c, m) retourner x
n
Méthode par congruence linéaire
// nombres courants pseudo-aléatoires int n ;
// congruence int M = 1000;
int a = 53;
int c = 97;
/********************************
* générateur pseudo-aléatoire basée sur la congruence
** entrée :
* graine du générateur aléatoire
** sortie :
* aucune
*******************************/
void randSeed(int _n) { n = _n;
}
Méthode par congruence linéaire
/********************************
* générateur pseudo-aléatoire basé sur la congruence
** entrée :
* aucune
** sortie :
* nombre non attendu suivant
*******************************/
int rand() { n = (a * n + c) % M;
return n;
}
void setup() { randSeed(23456);
println(rand());
println(rand());
}
Mersenne-twister (Makoto Matsumoto et Takuji Nishimura 1997)
Basé sur les nombres de Mersenne 2p−1 Période 219937−1
distribution uniforme sur 623 dimensions
N'est pas un générateur adapté à la cryptographie, mais très utile en simulation et optimisation.
Propriétés statistiques
Les générateurs pseudo-aléatoires génèrent des lois uniformes U(0,maxValue−1).
Certaines propriétés statistiques d'un générateur pseudo-aléatoire sont attendues :
Propriété de la distribution des nombres : moments, fréquence d'apparition des nombres, comparaison à la loi uniforme Entropie maximale
Indépendance statistique des nombres de la série : autocorrélation, test spectral
Générateur pseudo-aléatoires de nombres ottants
Initialisation de la graine aléatoire randomSeed(n)
Nombre aléatoire (oat) entre 0 et b (b exclu) random(b)
Nombre aléatoire (oat) entre a et b (b exclu) random(a, b)
Générateur pseudo-aléatoires de nombres entiers
Nombre aléatoire (int) entre 0 et b−1 int(random(b))
Nombre aléatoire (int) entre a et b−1 int(random(a, b))
Jeu où l'on doit deviner un nombre entre 0 et 100
Algorithme deviner() : rien début
variable a, n : entier n←???
a←n−1
tant que a6=n faire
a← lire("proposer un nombre") si a<n alors
écrire("trop petit") sinon
écrire("trop grand") n tant quen si
écrire("gagné") n
Jeu où l'on doit deviner un nombre entre 0 et 100
Algorithme deviner() : rien début
variable a, n : entier n←int(random(101)) a←n−1
tant que a6=n faire
a← lire("proposer un nombre") si a<n alors
écrire("trop petit") sinon
écrire("trop grand") n tant quen si
écrire("gagné")
Jeu où l'on doit deviner un nombre entre 0 et 100
/**************************************
* Organise le jeu qui consiste à deviner un nombre
** entrée :
* - n : nombre à deviner
** sortie :
* - aucune
***************************************/
void deviner() { int rep;
int n = int(random(101));
rep = n - 1;
while (rep != n) {
rep = lire("Proposer un nombre entier");
if (rep < n)
println("trop petit");
elseif (rep > n)
println("trop grand");
}
println("Gagné !");
}
Simulation de lancer de échettes
Simulation d'un lancé de n échettes sur une cible Algorithme lancer(n : entier) : entier
début
variable i, pts : entier variable ρ,θ : réel
pts ←0
pour i de 0 à n−1 faire ρ←random(10) θ←random(−π, π) point(ρcos(θ),ρsin(θ)) pts ← pts + points(ρ) n pour
retourner pts
Simulation de lancer de échettes
Algorithme points(d : réel) : entier début
si d > 10 alors retourner 0 sinon
si d > 5 alors retourner 3 sinon
si d > 2 alors retourner 5 sinon
si d > 1 alors retourner 10 sinon
retourner 20 n sin si
n sin si n
Simulation de lancer de échettes
/********************************
* lancer de n flechettes
** entrée :
* n : entier, nombre de lancer
** sortie :
* nombre points sur n lancers
*******************************/
int lancer(int n) { int pts = 0;
float rho, theta ; for(int i = 0; i < n; i++) {
rho = random(10);
theta = random(-3.14159265358, 3.14159265358);
point(width / 2 + 10 * rho * cos(theta), height / 2 + 10 * rho * sin(theta));
pts += nbPoints(rho);
} return pts;
}
Simulation de lancer de échettes
/********************************
* compte le nombre de point en fonction de la distance au centre
** entrée :
* rho : distance au centre
** sortie :
* nombre de point
*******************************/
int nbPoints(float rho) { if (rho > 10)
return 0;
elseif (rho > 5) return 3;
elseif (rho > 2) return 5;
elseif (rho > 1) return 10;
elsereturn 20;
}
Simulation de marche aléatoire
Simulation une marche aléatoire de n pas sur l'ensemble des entiers (positifs ou négatif) en partant du point central.
Algorithme marcheZ(x, y : entier) : rien début
si int(random(2)) == 0 alors y←y+1
sinon y←y−1
n sisi int(random(2)) == 0 alors x←x+1
sinon x←x−1 nn si
Simulation de marche aléatoire
// variable globale int x, y;
/********************************
* marche aléatoire sur Z^2
** entrée :
* aucune
** sortie :
* aucune
*******************************/
void marche() {
if (int(random(2)) == 0) elsey++;
y--;
if (int(random(2)) == 0) elsex++;
} x--;
Simulation de marche aléatoire
void draw() { // efface stroke(0);
point(x, y);
marche();
// affiche stroke(255);
point(x, y);
}
void setup() { size(200, 200);
background(0);
strokeWeight(20);
// position initiale y = height / 2;
x = width / 2;
frameRate(20);
}
Objectifs de la séance 6
Faire la diérence entre aléatoire et pseudo-aléatoire
Simuler un nombre pseudo-aléatoire entier ou ottant entre 2 bornes données
Ecrire un algorithme utilisant un générateur pseudo-aléatoire Ecrire un algorithme qui génère des séries temporelles du type ut+1 =aut+b+et ut+1 = (a+)ut+b
Question principale du jour :
Comment générer une série de nombres qui ont l'air d'être aléatoires ?