|
Site |
Cours VB.net |
|
|
|
Le Hasard, l'aléatoire |
|
|
???
Comment obtenir un nombre aléatoire?
A- Avec les instructions Rnd() et Randomize() de Visual Basic.Net
Rnd() fournit un nombre pseudo-aléatoire entre 0 et 1 (sans jamais atteindre 1); valeur inférieure à 1 mais supérieure ou égale à zéro; ce nombre pseudo-aléatoire est un Single.
En fait, si on fait des Rnd() successifs, le nombre pseudo-aléatoire précédemment généré est utilisé pour le calcul du nombre pseudo-aléatoire suivant (avec une formule mathématique complexe), ce qui fait que la suite de nombre pseudo-aléatoire est toujours la même et qu'elle est périodique (au bout d'un grand nombre de tirage, on recommence la même suite).
Randomize() initialise le générateur de nombres pseudo-aléatoires. Si on ne donne pas d'argument, Randomize utilise la valeur de l'horloge interne pour initialiser; cette valeur est dû au hasard, aussi le Rnd qui suit va être dû au hasard.
Si on n'utilisait pas Randomize() avant Rnd(), la fonction Rnd() fournirait toujours les mêmes nombres pseudo-aléatoire dans le même ordre.
En résumé:
Rnd , si il n'y a pas d'argument, fournit une suite de nombre pseudo aléatoire (le suivant étant calculé à partir du précédent), la suite est toujours la même, seule le premier change et est initialisé par Randomize qui est basé soit sur l'horloge système (et qui à priori initialise à une valeur toujours différente) s'il n'y a pas d'argument soit sur un argument.
Pour obtenir plusieurs fois les mêmes séries de nombres , utiliser Randomize avec un argument numérique puis appelez Rnd() avec un argument négatif.
Simuler un jeu de lancé de dé.
Comment obtenir un nombre entier entre un et six au hasard?
Dim MyValue As Integer
Randomize ' Initialise le générateur de nombre aléatoire.
MyValue = CInt(Int((6 * Rnd()) + 1)) ' Génère un nombre aléatoire entre 1 et 6.
Rnd() fournissant un nombre aléatoire entre 0 et 1, je le multiplie par 6 et j'ajoute 1 pour qu'il soit entre 1 et 7 sans atteindre 7 (il peut être entre 1 et 6,999), je prend sa valeur entière: il est maintenant entre 1 et 6, enfin je le transforme en Integer.
On transforme Int((6 * Rnd()) + 1) en Integer car Rnd(), ne l'oublions pas, retourne un Single.
B- Avec la classe Random du Framework
Il existe une classe(faisant partie de System ) nommée Random.
La méthode Next() retourne un Integer positif entre 0 et 2 147 483 647
La méthode NextDouble() retourne un Double entre 0 et 1.
La méthode NextBytes() retourne un Byte (octet)
On peut surcharger ces méthodes pour définir des bornes.
Exemple:
J'instancie une objet à partir de la classe.
Dim Al As New Random
L'objet Al est initialisé avec une valeur probablement liée au temps, à l'horloge interne, aussi l'initialisation est 'aléatoire'.
Pour obtenir un nombre(un double) entre 0 et 1 (toujours inférieur à 1)j'écris:
MonNombrealeatoire=Al.NextDouble
Ensuite chaque NextDouble génère le nombre pseudo-aléatoire suivant (à partir d'une formule)
Noter bien que dans ce qui précède, si on fait plusieurs fois Dim Al As New Random , le nombre obtenu par NextDouble n'est jamais le même.
Par contre si on fait:
Dim Al As New Random(1)
MonNombrealeatoire=Al.NextDouble
MonNombrealeatoire=Al.NextDouble
On obtient toujours:
'0.248668584157093'
'0.110743977181029'
On obtient donc la même série car on a imposé avec Random(1) une valeur de départ qui est fonction de (1) et non du temps.
Pour obtenir un nombre pseudo-aléatoire entre 0 et 10, on utilise Next:
Dim Al As New Random()
MonNombrealeatoire=Al.Next(10)
MonNombrealeatoire=Al.Next(10)
On obtient la série: 2, 1, 4, 7, 6, 4, 3, 9
On travaille sur des 'Integer'
Pour obtenir un nombre pseudo-aléatoire entre 5 et 10 (mais < à 10), on utilise Next:
Dim Al As New Random()
MonNombrealeatoire=Al.Next(5,10)
MonNombrealeatoire=Al.Next(5,10)
La série comportera les nombres integers 5, 6, 7, 8, 9 (pas 10)
Pour remplir un tableau d'octets avec des octets pseudo-aléatoires, on utilise NextBytes:
Dim rnd As New Random()
Dim b(10) As Byte
rnd.NextBytes(b)
C- En cryptographie avec le Framework
Pour remplir un tableau d'octets avec des octets aléatoires forts d'un point de vue cryptographique (pour générer un mot de passe par exemple), on utilise plutôt la classe RNGCryptoServiceProvider()
L'exemple suivant crée une séquence aléatoire de 100 octets de long et la stocke dans ra.
Imports
System.Security.Cryptography
Dim ra() As Byte = New Byte(100) {}
Dim rng As New RNGCryptoServiceProvider()
rng.GetBytes(ra) ' les octets dans ra sont maintenant aléatoires.
Il existe aussi GetNonZeroBytes pour ne pas avoir d'octet=0.
D - Un peu de théorie (creusons).

Un nombre aléatoire est obtenu par tirage au sort à égalité des chances, il est impossible de prévoir le tirage suivant.
Il existe des procédures physiques permettant de générer des nombres aléatoires: comptage de désintégration par compteur Geiger, analyse de bruit..
En informatique, on utilise les nombres pseudo aléatoires générés par des algorithmes.
L'implémentation actuelle de la classe Random est basée sur l'algorithme du générateur de nombres aléatoires soustractif de Donald E. Knuth. Pour plus d'information, consultez D. E. Knuth. « The Art of Computer Programming, volume 2: Seminumerical Algorithms. » Addision-Wesley, Reading, MA, deuxième édition, 1981.
Soit un nombre de départ x (nommé' graine' ou seed en anglais)
Le nombre est utilisé pour le calcul du nombre pseudo-aléatoire suivant (avec une formule mathématique complexe), ce qui fait que la suite de nombre pseudo-aléatoire est toujours la même pour une même graine et qu'elle est périodique.
La formule, dite générateur à congruence linéaire, pour trouver le nombre suivant, est de la forme:
Xn+1 = (aXn+b) mod m
xn+1 = (1 664 525 xn +
1 013 904 223) mod 232 (générateur de Knuth & Lewis)
Voir l'excellent article sur les nombres pseudo aléatoires:Article de P larbier
et l'excellent site de D. Müller
On a vu que le générateur est périodique: au bout d'un certain nombre de tirage pseudo-aléatoire, dés qu'un nombre apparaît la seconde fois, on recommence la même série. En théorie, la période maximale serait m (le m de mod m dans la formule) soit 232.
Quelle est la période de la Classe Random en pratique?
Période: 81 672 063 avec Next (Integer)
Période: 562 183 903 avec NextDouble (Double)
C'est un ordre de grandeur car en fonction de la graine (valeur de départ), la série et la période sont différentes (j'ai essayé!).
Tout l'art est de choisir la graine(le premier nombre) aléatoirement!!Cela est effectué par Randomize en VB ou l'instanciation d'un objet Random dans le Framework. Randomize utilise par exemple la valeur de l'horloge interne pour initialiser; cette valeur serait dû au hasard
Amélioration :
Comment générer des nombres plus aléatoires que les pseudo aléatoires?
1- Solution créée par le programmeur:
Le nombre aléatoire est la combinaison d'un nombre pseudo aléatoire et d'un nombre probablement aléatoire par exemple:
Position de la souris
Temps entre 2 pressions sur des touches
Statistique d'activité du disque dur.
Temps écoulé depuis.. (Ce que fait randomize).
Exemple:
Le nombre aléatoire est le produit d'un nombre pseudo aléatoire et du nombre de seconde écoulé depuis une date:
Dim pAlea As Double 'Nombre pseudo aléatoire
Dim second As Double 'Nombre de secondes depuis le 30/12/96
Dim Alea As Double 'Nombre aléatoire
Randomize
pAlea = Int((1000000 * Rnd) + 1)
second = DateDiff("s", "12/30/96", Now)
Alea = second *pAlea
Il y a des biais, en particulier, si on utilise régulièrement cette routine, le nombre de seconde est régulièrement croissant. On pourrait améliorer en utilisant second Mod quelque chose.
2- Solution proposée par le Framework:
Méthode utilisée dans la classe
System.Security.Cryptography
Le générateur doit
être capable de produire des nombres aléatoires résistant à des attaques ou à
des analyses
statistiques qui permettraient de prédire la suite.
Les méthodes courantes pour générer des nombres aléatoires en cryptographie consiste à utiliser diverses sources disponibles sur un ordinateur: temps entre deux accès au disque, taille de la mémoire, mouvements du pointeur de la souris... et à faire passer le résultat dans une fonction de hachage cryptographique comme MD5 ou SHA-1 puis à utiliser cette valeur comme graine puis...
|
|
|
|
|