Apprendre à créer des générateurs aléatoires en VBA

Denis Hulo

Objectif : apprendre à créer des générateurs aléatoires avec la fonction Rnd.

Niveau requis : confirmé

Commentez cet article : Commentez

- Titre : Apprendre à créer des générateurs aléatoires en VBA

- Auteur : Denis Hulo

- Parution : 3 novembre 2017

- Mise à jour : 7 juin 2020

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2017 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Fonction Rnd

- II-A. Fonction RndInteger

- III. Génération de chaînes de caractères aléatoires

- III-A. Fonction Chr

- III-B. Fonctions aléatoires

- III-B-1. Fonction RndNumChr

- III-B-2. Fonction RndLCaseLetter

- III-B-3. Fonction RndUCaseLetter

- III-B-4. Fonction RndSpecChr

- III-B-5. Fonction RndChr

- III-B-6. Fonction RndPwdChr

- III-B-7. Fonction RndString

- III-B-8. Fonction RndPwd

- III-C. Génération de mots de passe au hasard

- III-C-1. Table T_Utilisateur

- III-C-2. Fonction GenerateRandomPassword

- IV. Génération de séries d'événements aléatoires

- IV-A. Enregistrement des événements

- IV-B. Estimation du nombre d'événements de chaque type

- IV-B-1. Fonction NbTiragesMini

- IV-C. Génération de la série d'événements

- V. Génération d'arrangements aléatoires

- V-A. Table T_Arrangement

- V-B. Fonction GenerateArrangement

- V-C. Fonction GenerateArrangements

- V-D. Affichage de résultats

- VI. Créer son propre générateur de nombres aléatoires

- VI-A. Méthode de Fibonacci

- VI-A-1. Implémentation

- VI-A-1-a. Variables publiques x1 et x2

- VI-A-1-b. Procédure InitRandom

- VI-A-1-c. Fonction Random

- VI-B. Test de la fonction par la méthode de Monte-Carlo

- VI-B-1. Détermination de la valeur de Pi

- VI-B-1-a. Fonction Test

- VI-C. Note

- VII. Les bases de données à télécharger

- VIII. Remerciements

I - Introduction

Définitions utiles :

Le hasard ou aléa est un concept exprimant l'impossibilité de prévoir avec certitude un fait quelconque. Ainsi, pour éclairer le sens du mot, il est souvent dit que hasard est synonyme d'« imprévisibilité », ou « imprédictibilité ».
La probabilité est une valeur permettant de représenter le degré de certitude d'un événement aléatoire. Elle est comprise entre 0 et 1.

Après avoir présenté la fonction de génération de nombres aléatoires Rnd, nous proposerons des exemples d'application :

1. Générer des mots de passe au hasard ;

2. Génerer une série d'événements aléatoires ;

3. Générer des arrangements aléatoires.

Pour conclure, nous décrirons comment créer sa propre fonction de génération de nombres pseudoaléatoires en utilisant une méthode dite de Fibonacci.

Le code VBA est compatible avec Excel, même si tous les exemples sont réalisés avec Access.

II - Fonction Rnd

Extrait de l'aide sur la fonction Rnd :

Renvoie un nombre aléatoire de type Single inférieur à 1 et supérieur ou égal à 0.

Syntaxe : Rnd[(number)]

L'argument number est un numérique valide.

Si number est

Rnd génère

Inférieur à zéro

Le même nombre à chaque fois, en utilisant nombre comme la valeur de départ.

Supérieur à zéro

Nombre aléatoire suivant dans la séquence.

Égal à zéro

Le dernier nombre généré.

Non fourni

Nombre aléatoire suivant dans la séquence.

Avant d'appeler Rnd, utilisez l'instruction Randomize sans argument pour initialiser le générateur de nombres aléatoires avec une valeur initiale basée sur l'horloge système.

Parmi les générateurs de nombres aléatoires, celui qui s'est imposé avec l'avènement des ordinateurs est le générateur congruentiel linéaire. Partant d'un terme initial, il produit une suite de nombres dont chaque terme dépend du précédent, d'où la nécessité d'initialiser le générateur avant de l'utiliser.

II-A - Fonction RndInteger

Elle permet de générer un nombre entier au hasard.

Pour obtenir au hasard un entier compris dans une certaine plage délimitée par les entiers Mini et Maxi, on peut utiliser la formule :

Extrait de l'aide

Int((Maxi - Mini + 1) * Rnd + Mini)

On obtient donc aisément la fonction :

RndInteger

Function RndInteger(ByVal Mini As Long, ByVal Maxi As Long) As Long
RndInteger = Int((Maxi - Mini + 1) * Rnd + Mini)  ' Renvoie un nombre entier au hasard compris entre Mini et Maxi
End Function

À chaque appel de la fonction RndInteger, les entiers compris entre Mini et Maxi ont donc la même probabilité de sortir.

III - Génération de chaînes de caractères aléatoires

Pour générer ces chaînes de caractères au hasard, on va se baser sur la table des codes ASCII des 128 caractères, numérotés de 0 à 127 :

Table des codes ASCII

On se limitera donc volontairement, par la suite, aux caractères ASCII de 0 à 127. On remarquera également que « A » est inférieur à « a » dans la table et que les caractères 0 à 31 sont non imprimables.

III-A - Fonction Chr

L'idée est d'utiliser cette fonction pour renvoyer un caractère numérique (0, 1, 2, …, 9), une lettre, ou un caractère spécial, à partir du code ASCII.

Extrait de l'aide sur la fonction :

Chr(CharCode) retourne le caractère associé au code ASCII spécifié.

L'argument CharCode est un entier représentant le code du caractère. Si CharCode se trouve en dehors de la plage valide, une erreur ArgumentException se produit.

La plage valide pour Chr s'étend de 0 à 255.

En regardant les différents codes ASCII (colonne Dec) et leur caractère (colonne Char) affichés dans la table, on remarque que pour obtenir un caractère numérique (0, 1, …, 9), on passera à la fonction un entier compris entre 48 et 57. Pour obtenir un caractère alphabétique en majuscule (A, B, …, Z), on lui passera un entier compris entre 65 et 90. Enfin, pour obtenir un caractère alphabétique en minuscule, on choisira un entier entre 97 et 122.

III-B - Fonctions aléatoires

III-B-1 - Fonction RndNumChr

Elle permet de générer un caractère numérique au hasard.

Comme l'indique la table des codes ASCII, pour obtenir un caractère numérique, on doit passer à la fonction Chr un entier compris entre 48 et 57.

Codes ASCII correspondant aux chiffres

Codes ASCII

Caractères

48 à 57

0,1, 2, …, 9

La fonction RndNumChr, permettant de générer un caractère numérique au hasard, s'écrit donc :

Fonction RndNumChr

Function RndNumChr() as string
Dim i as Integer
i=RndInteger(48, 57) ' Code du caractère ASCII tiré au hasard entre 48 et 57
RndNumChr=Chr(i) ' Caractère ASCII correspondant
End Function

III-B-2 - Fonction RndLCaseLetter

Elle permet de générer une lettre minuscule au hasard.

Comme l'indique la table des codes ASCII, pour obtenir une lettre en minuscule au hasard, on doit passer à la fonction Chr un entier compris entre 97 et 122.

Codes ASCII correspondant aux lettres en minuscule

Codes ASCII

Caractères

97 à 122

a, b, c, …, …z

La fonction RndLCaseLetter, permettant de générer une lettre minuscule au hasard, s'écrit donc :

Fonction RndLCaseLetter

Function RndLCaseLetter() as string
Dim i as Integer
i=Int((122 - 97 + 1) * Rnd + 97) ' Code du caractère ASCII tiré au hasard
RndLCaseLetter=Chr(i) ' Caractère ASCII correspondant
End Function

III-B-3 - Fonction RndUCaseLetter

Elle permet de générer une lettre majuscule au hasard.

Comme l'indique la table des codes ASCII, pour obtenir une lettre en majuscule, on doit passer à la fonction Chr un entier compris entre 65 et 90.

Codes ASCII correspondant aux lettres en majuscule

Codes ASCII

Caractères

65 à 90

A, B,  C…, Z

La fonction RndUCaseLetter, permettant de générer une lettre majuscule au hasard, s'écrit donc :

Fonction RndUCaseLetter

Function RndUCaseLetter() as string
Dim i as Integer
i=Int((90 - 65 + 1) * Rnd + 65) ' Code du caractère ASCII tiré au hasard
RndUCaseLetter=Chr(i) ' Caractère ASCII correspondant
End Function

III-B-4 - Fonction RndSpecChr

Elle permet de générer un caractère spécial au hasard.

Pour obtenir un caractère spécial, cette fois-ci on doit passer en argument une chaîne contenant la liste des caractères spéciaux. Ensuite on tire au hasard l'indice de la position dans la chaîne, qui nous permet de retourner le caractère correspondant :

Fonction RndSpecChr

'********************************************************************************
'************** Fonction générant un caractère spécial au hasard ****************
'********************************************************************************
Function RndSpecChr(Optional s As String = "~!@#$%^&*()-_=+[]{};:,.<>/?") As String
' s : chaîne optionnelle contenant les caractères spéciaux autorisés
Dim i As Integer ' Indice indiquant la position dans la chaîne contenant les caractères spéciaux

i = RndInteger(1, Len(s)) ' Indice de position tiré au hasard

RndSpecChr = Mid(s, i, 1) ' Caractère spécial correspondant

End Function

III-B-5 - Fonction RndChr

Elle permet de générer au hasard un caractère ASCII dont le code est compris entre Mini et Maxi :

Fonction RndChr

Function RndChr(ByVal Mini As Variant, ByVal Maxi As Variant) As String
'---------------------------------------------------------------------------------------
' Mini = un code ASCII ou le caractère alpha.
' Maxi = un code ASCII ou le caractère alpha.
'---------------------------------------------------------------------------------------
' Retourne un caractère compris entre les bornes mini et maxi.
' Auteur : Laurent Ott
'---------------------------------------------------------------------------------------
' Cas particulier des chiffres 0 à 9 qu'il ne faut pas confondre des valeurs :
If Mini Like "[0-9]" Then Mini = Asc(Mini)
If Maxi Like "[0-9]" Then Maxi = Asc(Maxi)
' Convertir en valeur Asc les arguments passés en String :
If Val(Mini) = 0 Then Mini = Asc(Mini)
If Val(Maxi) = 0 Then Maxi = Asc(Maxi)

RndChr = Chr(RndInteger(Mini, Maxi))
End Function

III-B-6 - Fonction RndPwdChr

Elle permet de générer au hasard un caractère ASCII du type lettre minuscule, lettre majuscule, chiffre ou caractère spécial :

Fonction RndPwdChr

'********************************************************************************
'*************** Fonction générant un caractère ascii au hasard *****************
'********************************************************************************
Public Function RndPwdChr(ByVal c As String, Optional s As String = "~!@#$%^&*()-_=+[]{};:,.<>/?") As String
' s : chaîne optionnelle contenant les caractères spéciaux autorisés
' renvoie un caractère ascii au hasard
' en fonction du type de caractère ('l': lettre minuscule, 'L': lettre majuscule, 'c': chiffre, "s": caractère spéc.)

If StrComp(c, "l", vbBinaryCompare) = 0 Then ' Comparaison sensible à la casse
RndPwdChr = RndLCaseLetter  ' On génère au hasard une lettre minuscule

ElseIf StrComp(c, "L", vbBinaryCompare) = 0 Then
RndPwdChr = RndUCaseLetter ' On génère au hasard une lettre majuscule

ElseIf StrComp(c, "c", vbBinaryCompare) = 0 Then
RndPwdChr = RndNumChr  ' On génère au hasard un chiffre

ElseIf StrComp(c, "s", vbBinaryCompare) = 0 Then
RndPwdChr = RndSpecChr(s)  ' On génère au hasard un caractère spécial

End If

End Function

III-B-7 - Fonction RndString

Elle renvoie une chaîne de caractères aléatoire de NbCar éléments.

Les arguments acceptés par la fonction RndString sont :

- Nbcar : le nombre de caractères à générer ;

- ListeChoix : la liste des types de caractères (bornes mini et maxi), passés en caractères ou en code ASCII.

En résumé, voici le déroulé de la fonction :

1. Passage en argument de la liste des bornes délimitant les codes ASCII ;

2. Génération au hasard, à chaque passage de boucle, de l'indice de la liste passée en argument ;

3. Détermination des bornes Mini et Maxi correspondant à l'indice ;

4. Renvoi, en bout de chaîne, du résultat de la fonction aléatoire RndChr obtenu avec ces bornes ;

5. Après NbCar passages de boucles, renvoi de la chaîne complète obtenue.

Code de la fonction RndString

Public Function RndString(NbCar As Integer, ParamArray ListeChoix() As Variant) As String
'---------------------------------------------------------------------------------------
' NbCar = nombre de caractères à générer.
' ListeChoix = liste des types de caractères (bornes mini et maxi), passés en caractères
'              ou en code <i>ASCII</i>.
'---------------------------------------------------------------------------------------
' Retourne une chaîne de caractères aléatoires de NbCar éléments.
' Auteur : Laurent Ott
'---------------------------------------------------------------------------------------
Dim i As Integer, DansListe As Integer, Tps As Variant

' Boucle sur le nombre de caractères à retourner:
For i = 1 To NbCar
' Prend une liste au hasard:
DansListe = RndInteger(LBound(ListeChoix), UBound(ListeChoix))
' Retrouve la borne mini et maxi de cette liste:
Tps = Split(ListeChoix(DansListe), ",")
' Prend un caractère au hasard dans cette borne:
RndString = RndString & RndChr(Tps(0), Tps(1))
Next i
End Function

Exemples d'appels

RndString(1, "A,E") ' pour un caractère entre A et E.
RndString(1, "65,69") ' pour un caractère entre A et E.
RndString(1, "A,E", "G,J", "W,Z" ) ' pour un caractère entre A et E, ou entre G et J ou entre W et Z.

III-B-8 - Fonction RndPwd

Elle permet de générer une chaîne constituée de caractères tirés au hasard, il nous suffit de générer chacun des caractères au moyen des fonctions décrites précédemment.

Pour cela, la fonction prend en arguments des variables indiquant le nombre de caractères de chaque type à générer :

- NbCarMin : le nombre de lettres minuscules ;

- NbCarMaj : le nombre de lettres majuscules ;

- NbCarNum : le nombre de chiffres ;

- NbCarSpec : le nombre de caractères spéciaux.

En résumé, voici le déroulé de la fonction :

1. Passage en arguments du nombre de caractères par type ;

2. Constitution d'une chaîne contenant les codes correspondant aux types de caractères ;

3. Parcours des nbCar caractères de la chaîne dans une boucle ;

4. Génération au hasard, à chaque passage de boucle, de l'indice dans la chaîne ;

5. Pour chaque type de caractère, renvoi en bout de chaîne du résultat de la fonction aléatoire RndPwdChr ;

6. Après NbCar passages de boucles, renvoi de la chaîne complète obtenue.

Code de la fonction RndPwd

'********************************************************************************
'**************** Fonction générant un mot de passe aléatoire *******************
'********************************************************************************
Public Function RndPwd(ByVal NbCarMin As Integer, ByVal NbCarMaj As Integer, _
ByVal NbCarNum As Integer, ByVal NbCarSpec As Integer, _
Optional s As String = "~!@#$%^&*()-_=+[]{};:,.<>/?", _
Optional ByVal ident As Boolean = False, _
Optional ByVal remise As Boolean = True) As String
'---------------------------------------------------------------------------------------
' NbCarMin : Nombre de lettres minuscules
' NbCarMaj : Nombre de lettres majuscules
' NbCarNum : Nombre de chiffres
' NbCarSpec : Nombre de caractères spéciaux
' s : chaîne optionnelle contenant les caractères spéciaux autorisés
' ident : Indique si on autorise des caractères identiques
' remise : indique si le tirage a lieu avec ou sans remise
Dim nbCar As Integer ' nombre total de caractères à générer
Dim j As Integer ' Indice de position dans la chaîne
Dim str As String ' Chaîne contenant les abréviations associées aux types de caractères
Dim car As String * 1 ' Caractère à ajouter en bout de chaîne

nbCar = NbCarMin + NbCarMaj + NbCarNum + NbCarSpec ' évaluation du nombre total de caractères à générer

str = String(NbCarMin, "l") + String(NbCarMaj, "L") + _
String(NbCarNum, "c") + String(NbCarSpec, "s")   ' Création de la chaîne en fonction du nombre de caractères de chaque type.

' Boucle sur le nombre de caractères à retourner
While nbCar > 0

j = RndInteger(1, nbCar) ' On choisit au hasard l'indice dans la chaîne contenant les types de caractères _
' 1: lettre minuscule; L: lettre majuscule; c: chiffre; s: caractère spécial
car = RndPwdChr(Mid(str, j, 1), s) ' On passe à la fonction le caractère correspondant à son type.

' Si le caractère n'a pas déjà été généré dans le cas où on n'autorise pas de répétition.
If (ident Or (InStr(1, RndPwd, car, 0) = 0)) Then
RndPwd = RndPwd & car ' Copie du caractère à la fin de la chaîne
If Not remise Then ' Si sans remise
str = Left(str, j - 1) & Mid(str, j + 1) ' Supprime le caractère d'indice j dans la chaîne str.
End If
nbCar = nbCar - 1
End If

Wend

End Function

Exemple d'appel

RndPwd(4, 4, 2, 2) ' Pour 4 lettres minuscules, 4 majuscules, 2 chiffres et 2 caractères spéciaux

Vous pouvez facilement définir si le tirage a lieu avec ou sans remise avec le dernier argument de la fonction.

III-C - Génération de mots de passe au hasard

Le principe est de générer une chaîne de caractères aléatoire à l'aide de la fonction RndPwd et de tester s'il est présent dans une table. S'il n'est pas présent, on l'ajoute dans la table, sinon on en génère un autre, jusqu'à ce qu'il ne soit pas présent.

III-C-1 - Table T_Utilisateur

On utilise pour cela une table T_Utilisateur qui va contenir les nom et prénom des utilisateurs, accompagnés de leur mot de passe :

T_Utilisateur

Nom du champ

Type du champ

Description

IdUtilisateur

Entier long

Identifiant de l'utilisateur

NomUtilisateur

Texte

Nom de l'utilisateur

PrenomUtilisateur

Texte

Prénom de l'utilisateur

MotDePasse

Texte

Mot de passe de l'utilisateur

Exemple de données :

Affichage des données

IdUtilisateur

NomUtilisateur

PrenomUtilisateur

MotDePasse

1

Dupont

Jean

pmH5X6XLfk

2

Durand

Ludovic

7sBEkiN1Aw

3

Martin

Olivier

qFh4AkBN0l

..

..

..

..

III-C-2 - Fonction GenerateRandomPassword

Fonction principale qui va appeler la précédente pour composer la chaîne de caractères constituant le mot de passe.

En résumé, voici le déroulé de la fonction principale :

1. Ouverture du recordset pour l'ajout du mot de passe dans la table ;

2. Génération d'un nouveau mot de passe tant que celui-ci est présent dans la base ;

3. Sortie de la boucle une fois que la chaîne générée n'est pas présente dans la base ;

4. Ajout de la séquence de caractères constituant le mot de passe dans la table.

Code de la fonction GenerateRandomPassword

'********************************************************************************
'*********** Fonction principale générant un mot de passe aléatoire *************
'********************************************************************************
Public Function GenerateRandomPassword(ByVal nomUtilisateur As String, ByVal prenomUtilisateur As String) As Boolean
On Error GoTo err_GenerateRandomPassword
Dim db As DAO.Database ' Variable faisant référence à la base de données courante
Dim rs As DAO.Recordset ' Recordset basé sur la table T_Utilisateur
Dim pwd As String ' Variable contenant le mot de passe

Set db = CurrentDb
Set rs = db.OpenRecordset("T_Utilisateur", dbOpenDynaset) ' Ouverture du recordset basé sur la table T_Utilisateur

Randomize ' Initialisation du générateur de nombres aléatoires

pwd = RndPwd(4, 4, 2, 2) ' Génération de la chaîne alphanumérique en fonction des paramètres passés en argument

rs.FindFirst "MotDePasse like '" & pwd & "'" ' Recherche si le mot de passe existe dans la table

Do While Not rs.NoMatch ' Si déjà présent
pwd = RndPwd(4, 4, 2, 2)      ' Génération de la chaîne alphanumérique en fonction des paramètres passés en argument

rs.FindFirst "MotDePasse like '" & pwd & "'"
Loop

' La variable pwd contient une chaîne non présente dans la base

rs.AddNew ' Ajout dans la base du mot de passe et des identifiants
rs!nomUtilisateur = nomUtilisateur
rs!prenomUtilisateur = prenomUtilisateur
rs!MotDePasse = pwd
rs.Update

' Libération des variables

rs.Close
Set rs = Nothing

Set db = Nothing

GenerateRandomPassword = True ' Sortie avec la valeur True

Exit Function
err_GenerateRandomPassword:     ' Gestion d'erreur
If Err.Number <> 0 Then
MsgBox (Err.Description) ' Affichage de l'erreur
GenerateRandomPassword = False ' Sortie avec la valeur False (d’ailleurs ce n’est pas utile !)
End If

End Function

Étant développeur VBA Access, j'utilise le modèle objet DAO plutôt que ADO, car il est plus adapté au logiciel Access.

IV - Génération de séries d'événements aléatoires

On souhaite générer et enregistrer dans une table, une série d'événements ayant chacun une certaine probabilité d'advenir.

Voici les différentes étapes du processus :

1. Enregistrer dans une table les événements et leur probabilité ;

2. Évaluer le nombre d'événements du même type à générer en fonction de leur probabilité ;

3. Générer la liste des événements dans une table temporaire ;

4. Tirer au hasard les événements dans la table temporaire, pour les ajouter à la table T_SerieAlea.

On prendra en compte des tirages successifs avec ou sans remise.

IV-A - Enregistrement des événements

On utilise pour cela une table T_Evenement :

T_Evenement

Nom du champ

Type du champ

Description

IdEvenement

Entier long

Identifiant de l'événement

NomEvenement

Texte

Nom de l'événement

ProbaEvenement

Réel simple

Estimation de la probabilité de l'événement, comprise entre 0 et 1

Exemple de données :

Affichage des données

IdEvenement

NomEvenement

ProbaEvenement

1

A

0.1

2

B

0.25

3

C

0.25

4

D

0.4

IV-B - Estimation du nombre d'événements de chaque type

On va obtenir le nombre d'événements de chaque type à partir de leur probabilité d'advenir et du nombre total de tirages successifs à effectuer.

Si le nombre total de tirages est omis, on calcule à la place un nombre minimum permettant d'avoir les bonnes quantités de chaque :

Dans un premier temps, on multiplie la probabilité par une puissance de 10 pour supprimer la virgule et obtenir uniquement des entiers :

Multiplication par 100

IdEvenement

NomEvenement

Nombre représentatif

1

A

0.1*100=10

2

B

0.25*100=25

3

C

0.25*100=25

4

D

0.4*100=40

Puis, on détermine le PGCD entre 10, 25, 25 et 40, afin de simplifier ces résultats. Ici, on constate qu'ils se divisent par 5 :

Division par 5

IdEvenement

NomEvenement

Nombre représentatif

1

A

10/5=2

2

B

25/5=5

3

C

25/5=5

4

D

40/5=8

Les valeurs obtenues (2, 5, 5 et 8) constituent, en les additionnant, le nombre minimum de tirages nécessaires :

2 + 5 + 5 + 8 = 20

En conclusion, dans ce cas, pour obtenir les bonnes quantités de chaque, on aura donc besoin d'effectuer un nombre de tirages n qui soit un multiple de 20.

IV-B-1 - Fonction NbTiragesMini

Elle va permettre d'obtenir le nombre minimum de tirages nécessaires.

Déroulé de la fonction :

1. Déterminer le nombre maximum de chiffres après la virgule parmi les valeurs de probabilité ;

2. Évaluer la puissance de 10 permettant d'éliminer la virgule pour toutes les valeurs de probabilité ;

3. Déterminer, parmi les valeurs entières obtenues, le plus grand commun diviseur ;

4. Diviser la puissance de 10 par le PGCD pour obtenir le nombre minimum de tirages nécessaires.

Code de la fonction NbTiragesMini

'********************************************************************************
'************** Retourne le nombre minimum de tirages nécessaires ***************
'********************************************************************************
Public Function NbTiragesMini(rs As DAO.Recordset) As Long
'rs : argument recordset basé sur la table T_Evenement
On Error GoTo err_NbTiragesMini
Dim n1 As Long, n2 As Long
Dim n As Long, i As Long, n_dec As Long, d As Long

n_dec = DMax("Len(ProbaEvenement)", "T_Evenement") - 2 ' Renvoie le nombre maximum de chiffres après la virgule

n = 10 ^ n_dec ' Puissance de 10 nécessaire permettant d'éliminer la virgule après multiplication d'avec la probabilité

n1 = rs!ProbaEvenement * n ' On obtient le nombre entier représentatif de cette probailité
rs.MoveNext ' Enregistrement suivant

Do Until rs.EOF

n2 = rs!ProbaEvenement * n

d = PGCD(n1, n2) ' On obtient le PGCD (plus grand commun diviseur) entre le 1er et le 2e nombre

n1 = d ' Le 1er nombre devient le PGCD des 2 précédents nombres.

rs.MoveNext ' Enregistrement suivant

Loop

rs.MoveFirst

NbTiragesMini = n \ d ' Restitution du résultat de la fonction

Exit Function

err_NbTiragesMini:         ' Gestion d'erreur
MsgBox (Err.Description)
NbTiragesMini = 0 ' On retourne 0 en cas d'erreur

End Function

IV-C - Génération de la série d'événements

On va constituer la série des événements aléatoires à partir de leur probabilité pour un tirage avec ou sans remise.

Déroulé de la fonction :

1. Vidage de la table temporaire T_EvenementTmp ;

2. Ajout des événements dans la table temporaire T_EvenementTmp, en fonction de leur probabilité contenue dans la table T_Evenement ;

3. Tirage au hasard des événements dans la table temporaire, pour les ajouter à la table T_SerieAlea.

Code de la fonction GenerateRandomEventsSeries

'********************************************************************************
'************* Fonction générant une série d'événements aléatoires **************
'********************************************************************************
Public Function GenerateRandomEventsSeries(ByVal remise As Boolean, Optional n_total As Long = 0) As Boolean
On Error GoTo err_GenerateRandomEventsSeries
'remise: Argument pour spécifier si le tirage a lieu avec ou sans remise
'n_total: Argument optionnel pour définir une estimation du nombre total d'événements a générer
Dim db As DAO.Database ' Variable objet faisant référence à la base de donnée
Dim rsEvents As DAO.Recordset ' Recordset faisant référence la table T_Evenement
Dim rsEventsTmp As DAO.Recordset ' Recordset faisant référence à la table temporaire T_EvenementTmp
Dim rsSerie As DAO.Recordset ' Recordset faisant référence à la table T_SerieAlea
Dim n_event As Long ' Nombre d'événements du même type générés
Dim i As Long ' Variable d'indice pour les enregistrements de la table temporaire
Dim j As Long ' Variable d'indice pour un enregistrement de la table temporaire tiré au hasard
Dim n As Long ' Variable d'indice pour le dernier enregistrement de la table temporaire

Set db = CurrentDb ' Pointe sur la base de données courante

db.Execute "delete * from T_EvenementTmp;", dbFailOnError ' Suppression des enregistrements de la table temporaire

Set rsEvents = db.OpenRecordset("T_Evenement", dbOpenSnapshot) ' Ouverture du recordset basé sur la table T_Evenement
Set rsEventsTmp = db.OpenRecordset("T_EvenementTmp", dbOpenDynaset) ' Ouverture du recordset basé sur la table temporaire T_EvenementTmp
Set rsSerie = db.OpenRecordset("T_SerieAlea", dbOpenDynaset) ' Ouverture du recordset basé sur la table T_SerieAlea

rsEvents.MoveFirst

If (n_total = 0) Then ' Si le nombre total de tirages n'a pas été fixé au départ
n_total = NbTiragesMini(rsEvents) ' Calcul du nombre minimum de tirages nécessaires
End If

' Ajout des événements aléatoires en fonction de leur probabilité dans la table temporaire T_EvenementTmp
Do Until rsEvents.EOF

n_event = CInt(n_total * rsEvents!ProbaEvenement) ' Nombre d'événements du même type

For i = 1 To n_event ' On ajoute cet événement dans la table temporaire autant de fois que n_event
rsEventsTmp.AddNew
rsEventsTmp!IdEvenement = rsEvents!IdEvenement
rsEventsTmp.Update
Next i

rsEvents.MoveNext ' On passe à l'enregistrement suivant dans la table T_Evenement

Loop

rsEventsTmp.MoveLast
rsEventsTmp.MoveFirst

n = rsEventsTmp.RecordCount - 1 ' Détermine le nombre total d'enregistrement -1

db.Execute "delete * from T_SerieAlea;", dbFailOnError ' Supprime les événements précédents de la table

Randomize ' Initialisation du générateur de nombre aléatoire

For i = 0 To n

j = RndInteger(0, n) ' Tire au hasard un entier entre 0 et n (indices des enregistrements de la table temporaire)

rsEventsTmp.Move j ' Se déplace sur l'enregistrement choisi au hasard et d'indice j

' Ajoute l'enregistrement à la table T_Evenement
rsSerie.AddNew
rsSerie!IdSerie = i + 1 ' Numéro de l'événement
rsSerie!IdEvenement = rsEventsTmp!IdEvenement ' Identifiant de l'événement
rsSerie.Update

If Not remise Then ' Si tirage sans remise
rsEventsTmp.Delete ' Suppression de l'enregistrement d'indice j de la table temporaire
n = n - 1 ' Décompte de l'indice maximum de la table temporaire
End If

rsEventsTmp.MoveFirst

Next i

' Libération des variables

rsEvents.Close
Set rsEvents = Nothing

rsEventsTmp.Close
Set rsEventsTmp = Nothing

rsSerie.Close
Set rsSerie = Nothing

Set db = Nothing

GenerateRandomEventsSeries = True ' Renvoie True

Exit Function

err_GenerateRandomEventsSeries:     ' Gestion de l'erreur
MsgBox (Err.Description) ' Affichage de la description de l'erreur
GenerateRandomEventsSeries = False ' Renvoie False en cas d'erreur

End Function

On peut également optimiser la fonction en utilisant une collection à la place de la table temporaire :

Code de la fonction GenerateRandomEventsSeriesV2

'********************************************************************************
'******* Fonction générant une série d'événements aléatoires version n°2 ********
'********************************************************************************
Public Function GenerateRandomEventsSeriesV2(ByVal remise As Boolean, Optional n_total As Long = 0) As Boolean
On Error GoTo err_GenerateRandomEventsSeriesV2
'remise: Argument pour spécifier si le tirage a lieu avec ou sans remise
'n_total: Argument optionnel pour définir une estimation du nombre total d'événements a générer
Dim db As DAO.Database ' Variable objet faisant référence à la base de donnée
Dim rsEvents As DAO.Recordset ' Recordset faisant référence la table T_Evenement
Dim rsSerie As DAO.Recordset ' Recordset faisant référence à la table T_SerieAlea
Dim cl As Collection ' Collection dans laquelle on va copier les identifiants des événements dans les bonnes proportions
Dim n_event As Long ' Nombre d'événements du même type générés
Dim i As Long ' Variable d'indice pour les éléments de la collection
Dim j As Long ' Variable d'indice pour un élément tiré au hasard
Dim n As Long ' Variable d'indice pour le dernier élément de la collection

Set db = CurrentDb ' Pointe sur la base de données courante

Set rsEvents = db.OpenRecordset("T_Evenement", dbOpenSnapshot) ' Ouverture du recordset basé sur la table T_Evenement
Set rsSerie = db.OpenRecordset("T_SerieAlea", dbOpenDynaset) ' Ouverture du recordset basé sur la table T_SerieAlea

Set cl = New Collection

rsEvents.MoveFirst

If (n_total = 0) Then ' Si le nombre total de tirages n'a pas été fixé au départ
n_total = NbTiragesMini(rsEvents) ' Calcul du nombre minimum de tirages nécessaires
End If

' Ajout des événements en fonction de leur probabilité dans la collection
Do Until rsEvents.EOF

n_event = CInt(n_total * rsEvents!ProbaEvenement) ' Nombre d'événements du même type

For i = 1 To n_event ' On ajoute cet événement dans la collection autant de fois que n_event
cl.Add (rsEvents!IdEvenement)
Next i

rsEvents.MoveNext ' On passe à l'enregistrement suivant dans la table T_Evenement

Loop

n = cl.Count ' Détermine le nombre total d'éléments de la collection

db.Execute "delete * from T_SerieAlea;", dbFailOnError ' Supprime les événements précédents de la table

Randomize ' Initialisation du générateur de nombre aléatoire

For i = 1 To n

j = RndInteger(1, n) ' Tire au hasard un entier entre 0 et n (indices des enregistrements de la table temporaire)

' Ajoute l'enregistrement à la table T_Evenement
rsSerie.AddNew
rsSerie!IdSerie = i ' Numéro de l'événement
rsSerie!IdEvenement = cl.Item(j) ' Identifiant de l'événement
rsSerie.Update

If Not remise Then ' Si tirage sans remise
cl.Remove (j) ' Suppression de l'élément d'indice j de la collection
n = n - 1 ' Décompte de l'indice maximum de la collection
End If

Next i

' Libération des variables objet

Set cl = Nothing

rsEvents.Close
Set rsEvents = Nothing

rsSerie.Close
Set rsSerie = Nothing

Set db = Nothing

GenerateRandomEventsSeriesV2 = True ' Renvoie True

Exit Function

err_GenerateRandomEventsSeriesV2:     ' Gestion de l'erreur
MsgBox (Err.Description) ' Affichage de la description de l'erreur
GenerateRandomEventsSeriesV2 = False ' Renvoie False en cas d'erreur

End Function

V - Génération d'arrangements aléatoires

On souhaite tirer au hasard l'ensemble des dispositions possibles de n ouvriers sur p machines, afin d'évaluer celle qui offre le meilleur rendement. Les données des ouvriers sont enregistrées dans une table T_Personne (NumPersonne, NomPersonne), et celles des machines sont sauvegardées dans une table T_Machine (NumMachine, NomMachine).

Voici les différentes étapes du processus de génération des arrangements :

1. Enregistrer, dans les tables correspondantes, des données concernant les personnes et les machines ;

2. Déterminer les paramètres n et p du nombre m d'arrangements ;

3. Parcourir, dans une boucle, les m arrangements ;

4. À chaque passage de boucle, tirer au hasard une série de p numéros de personnes distincts ;

5. Si cette série n'a pas déjà été tirée, la retenir, sinon effectuer un nouveau tirage ;

6. Pour chaque arrangement obtenu, l'enregistrer dans une table.

Dans ce cas, il s'agit de tirages successifs sans remise. Le nombre de résultats possibles est donné par une formule mathématique appelée arrangements.

V-A - Table T_Arrangement

Table permettant d'enregistrer les différentes dispositions de n personnes sur p machines.

T_Arrangement

Nom du champ

Type du champ

Description

NumArrangement

Entier long

Numéro de l'arrangement

NumMachine

Entier long

Numéro de la machine

NumPersonne

Entier long

Numéro de la personne

V-B - Fonction GenerateArrangement

Pour simplifier, on va commencer par tirer au hasard p personnes parmi n, pour les placer sur p machines. Cela revient à générer un seul arrangement.

Déroulé de la fonction :

1. Déterminer les paramètres n et p correspondant aux nombres d'enregistrements contenus dans les tables T_Personne et T_Machine ;

2. Copier les numéros des n personnes dans une collection ;

3. Tirer au hasard dans cette colllection une série de p numéros de personnes distincts pour les enregistrer suivant l'ordre des machines.

Code de la fonction GenerateArrangement

'********************************************************************************
'****************** Fonction générant un arrangement au hasard ******************
'********************************************************************************
Public Function GenerateArrangement() As Long
On Error GoTo err_GenerateArrangement
Dim db As DAO.Database ' Variable pour faire référence à la base de données courante
Dim rsPersonnes As DAO.Recordset ' Recordset basé sur la table T_Personne
Dim rsMachines As DAO.Recordset ' Recordset basé sur la table T_Machine
Dim rsArrangements As DAO.Recordset ' Recordset basé sur la table T_Arrangement
Dim numPersonne As Long ' Numéro de la personne
Dim c As Collection ' Collection pour enregistrer les numéros de personnes
Dim i As Long, j As Long ' Indices pour parcourir les éléments du tableau et de la collection
Dim n As Long, p As Long ' Paramètres définisant le nombre d'arrangements

Set db = CurrentDb ' Référence à la base courante

db.Execute "delete * from T_Arrangement;", dbFailOnError  ' Suppression des anciens arrangements

Set rsPersonnes = db.OpenRecordset("T_Personne", dbOpenSnapshot) ' Ouverture du recordset basé sur la table T_Personne
Set rsMachines = db.OpenRecordset("T_Machine", dbOpenSnapshot) ' Ouverture du recordset basé sur la table T_Personne
Set rsArrangements = db.OpenRecordset("T_Arrangement", dbOpenDynaset) ' Ouverture du recordset basé sur la table T_Placement

rsPersonnes.MoveLast
rsPersonnes.MoveFirst

rsMachines.MoveLast
rsMachines.MoveFirst

n = rsPersonnes.RecordCount ' Nombre total de personnes
p = rsMachines.RecordCount ' Nombre total de machines

Set c = New Collection ' Création de l'objet Collection

Randomize ' Initialisation du générateur de nombre aléatoire

rsPersonnes.MoveFirst

' On enregistre dans la collection les numéros des n personnes
Do Until rsPersonnes.EOF
c.Add (rsPersonnes!numPersonne)
rsPersonnes.MoveNext
Loop

For i = 1 To p ' On procède à p tirages au sort des personnes pour les placer sur p machines

j = RndInteger(1, (c.Count)) ' Tirage au hasard d'un entier compris entre 1 et c.Count (nombre d'éléments de la collection)
numPersonne = c.Item(j)

' On enregistre le numéro de la personne dans l'ordre des numéros de machines
rsArrangements.AddNew
rsArrangements!numArrangement = 1
rsArrangements!NumMachine = rsMachines!NumMachine
rsArrangements!numPersonne = numPersonne
rsArrangements.Update

rsMachines.MoveNext ' passe à la machine suivante

c.Remove (j) ' Suppression de l'élément de la collection

Next i

' On libère les variables

Set c = Nothing

rsPersonnes.Close
Set rsPersonnes = Nothing

rsMachines.Close
Set rsMachines = Nothing

rsArrangements.Close
Set rsArrangements = Nothing

Set db = Nothing

GenerateArrangement = True ' On renvoie true si pas d'erreur

Exit Function ' Sortie de la fonction

err_GenerateArrangement:  ' Gestion de l'erreur
MsgBox (Err.Description) ' Affichage de la description de l'erreur
GenerateArrangement = False ' On renvoie false en cas d'erreur

End Function

V-C - Fonction GenerateArrangements

On souhaite maintenant tirer au hasard l'ensemble des dispositions possibles de n personnes sur p machines.

Déroulé de la fonction :

1. Déterminer les paramètres n et p des arrangements correspondant aux nombres d'enregistrements contenus dans les tables T_Personne et T_Machine ;

2. Parcourir, dans une boucle, les m arrangements, m étant obtenu avec la fonction Arrangements(n,p) ;

3. À chaque passage de boucle, copier les numéros de personnes dans une collection ;

4. À chaque passage de boucle, tirer au hasard une série de p numéros de personnes distincts ;

5. Si cette série n'a pas déjà été tirée, la retenir en la copiant dans la table T_ArrangementTmp, sinon effectuer un nouveau tirage ;

6. Pour chaque arrangement obtenu, l'enregistrer dans la table T_Arrangement.

Code de la fonction GenerateArrangements

'********************************************************************************
'**************** Fonction générant des arrangements aléatoires *****************
'********************************************************************************
Public Function GenerateArrangements() As Long
On Error GoTo err_GenerateArrangements
Dim db As DAO.Database ' Variable pour faire référence à la base de données courante
Dim rsPersonnes As DAO.Recordset ' Recordset basé sur la table T_Personne
Dim rsMachines As DAO.Recordset ' Recordset basé sur la table T_Machine
Dim rsArrangementsTmp As DAO.Recordset ' Recordset basé sur la table temporaire T_ArrangementTmp
Dim rsArrangements As DAO.Recordset ' Recordset basé sur la table T_Arrangement
Dim numPersonne As Long ' Numéro de la personne
Dim numArrangement As Long ' Numéro de l'arrangement, sert à parcourir les arrangements
Dim c As Collection ' Collection pour enregistrer les numéros de personnes
Dim s As String ' Chaîne de caractères contenant l'arrangement
Dim t As Variant ' Tableau contenant les numéros de personnes constituant l'arrangement
Dim i As Long, j As Long ' Indices pour parcourir les éléments du tableau et de la collection
Dim n As Long, p As Long ' Paramètres définisant le nombre d'arrangements
Dim m As Long ' Nombre d'arrangements
Dim cpt As Long

Set db = CurrentDb ' Référence à la base courante

db.Execute "delete * from T_ArrangementTmp;", dbFailOnError ' Suppression des anciennes configurations
db.Execute "delete * from T_Arrangement;", dbFailOnError  ' Suppression des anciens arrangements

Set rsPersonnes = db.OpenRecordset("T_Personne", dbOpenSnapshot) ' Ouverture du recordset basé sur la table T_Personne
Set rsMachines = db.OpenRecordset("T_Machine", dbOpenSnapshot) ' Ouverture du recordset basé sur la table T_Personne
Set rsArrangementsTmp = db.OpenRecordset("T_ArrangementTmp", dbOpenDynaset) ' Ouverture du recordset basé sur la table temporaire T_ArrangementTmp
Set rsArrangements = db.OpenRecordset("T_Arrangement", dbOpenDynaset) ' Ouverture du recordset basé sur la table T_Placement

rsPersonnes.MoveLast
rsPersonnes.MoveFirst

rsMachines.MoveLast
rsMachines.MoveFirst

n = rsPersonnes.RecordCount ' Nombre total de personnes
p = rsMachines.RecordCount ' Nombre total de machines

m = Arrangements(n, p) ' Nombre d'arrangements de p personnes prises parmi n
cpt = 0
Set c = New Collection ' Création de l'objet Collection

Randomize ' Initialisation du générateur de nombre aléatoire

For numArrangement = 1 To m ' On parcourt les m arrangements

Do ' Pour chaque arrangement on procède à un tirage des p éléments

rsPersonnes.MoveFirst

' On enregistre dans la collection les numéros des n personnes
Do Until rsPersonnes.EOF
c.Add (rsPersonnes!numPersonne)
rsPersonnes.MoveNext
Loop

s = vbNullString ' On initialise la chaîne de caractères

For i = 1 To p ' On procède à p tirages au sort des personnes pour les placer sur p machines

j = RndInteger(1, (c.Count)) ' Tirage au hasard d'un entier compris entre 1 et c.Count (nombre d'éléments de la collection)
numPersonne = c.Item(j)

s = s & numPersonne & "," ' Ajout du numéro de la personne en bout de chaîne

c.Remove (j) ' Suppression de l'élément de la collection

Next i

' Suppression des éléments de la collection
Do While c.Count > 0
c.Remove (1)
Loop

s = Left(s, Len(s) - 1) ' On enlève le denier caractère de la chaîne, la virgule.
cpt = cpt + 1
rsArrangementsTmp.FindFirst "Arrangement like '" & s & "'" ' On vérifie si cet arrangement a déjà été tiré

Loop Until (rsArrangementsTmp.NoMatch) ' Si non, on sort de la boucle pour ajouter cet arrangement

' Ajout de l'arrangement à la table temporaire T_ArrangementTmp
rsArrangementsTmp.AddNew
rsArrangementsTmp!Arrangement = s
rsArrangementsTmp.Update

t = Split(s, ",") ' On créé, à partir de la chaîne, le tableau comportant les numéros de personnes composant l'arrangement.

rsMachines.MoveFirst
i = 0

' On ajoute l'arrangement à la table T_Arrangement
Do Until rsMachines.EOF
rsArrangements.AddNew
rsArrangements!numArrangement = numArrangement
rsArrangements!NumMachine = rsMachines!NumMachine
rsArrangements!numPersonne = CLng(t(i))
rsArrangements.Update
rsMachines.MoveNext
i = i + 1
Loop

Next numArrangement ' On passe au suivant

' On libère les variables

Set c = Nothing

rsPersonnes.Close
Set rsPersonnes = Nothing

rsMachines.Close
Set rsMachines = Nothing

rsArrangementsTmp.Close
Set rsArrangementsTmp = Nothing

rsArrangements.Close
Set rsArrangements = Nothing

Set db = Nothing

GenerateArrangements = cpt ' On renvoie le nombre d'essais nécessaires

Exit Function ' Sortie de la fonction

err_GenerateArrangements:  ' Gestion de l'erreur
MsgBox (Err.Description) ' Affichage de la description de l'erreur
GenerateArrangements = False ' On renvoie false en cas d'erreur

End Function

V-D - Affichage de résultats

Extrait des résultats de la requête R_Arrangements, avec quatre personnes et trois machines :

R_Arrangements

NumArrangement

NumMachine

NomMachine

NumPersonne

NomPersonne

1

1

M1

3

Martin

1

2

M2

2

Durand

1

3

M3

1

Dupont

2

1

M1

1

Dupont

2

2

M2

3

Martin

2

3

M3

2

Durand

..

..

..

..

..

23

1

M1

1

Dupont

23

2

M2

3

Martin

23

3

M3

4

Ruffin

24

1

M1

4

Ruffin

24

2

M2

3

Martin

24

3

M3

2

Durand

La requête R_Arrangements relie les tables T_Arrangement, T_Machine et T_Personne.

VI - Créer son propre générateur de nombres aléatoires

Si on reprend la définition du début, on peut dire que le hasard est synonyme d'« imprévisibilité », ou « imprédictibilité ». Or, aucune fonction écrite par l'homme ne peut-être absolument imprédictible. Il suffit de connaître l'algorithme pour prévoir son résultat, et la fonction Rnd n'échappe pas à la règle.

On se propose donc d'écrire notre propre fonction de génération de nombres pseudoaléatoires.

VI-A - Méthode de Fibonacci

Cette méthode est basée sur la suite de Fibonacci modulo la valeur maximale désirée, elle a l'avantage d'être très simple à implémenter et ne consomme que peu de ressources :

Formule de Fibonacci

x(n) = (x(n-2) + x(n-1)) mod M

Où x(n) désigne la variable d'indice n, x(0) et x(1) correspondent aux valeurs initiales entrées au début du processus aléatoire, et M est la valeur maximale pouvant être générée.

Pour plus de détails, vous pouvez consulter cette page.

VI-A-1 - Implémentation

Description du principe :

1. Initialisation des variables x1 et x2 au moyen de la procédure InitRandom ;

2. Mise à jour de x1 et x2 avec la formule dite de Fibonacci à chaque appel de la fonction Random.

VI-A-1-a - Variables publiques x1 et x2

Ces variables sont déclarées en haut du module contenant les fonctions. Cela permettra de les mettre à jour et de les transmettre dans les routines InitRandom et Random.

Option Compare Database
Option Explicit

' Variables représentant les 2 termes de la formule de Fibonacci et utilisées dans les fonctions IniRandom et Random.
Dim x1 As Long, x2 As Long
...

VI-A-1-b - Procédure InitRandom

Cette procédure permet d'initialiser le générateur de nombres aléatoires en mettant à jour les deux variables x1 et x2 avec la fonction Timer.

Fonction InitRandom

'********************************************************************************
'******************* Procédure d'initialisation du générateur *******************
'********************************************************************************
Public Sub InitRandom()
Dim x As Single

x = Timer * 100 ' On prend comme valeur aléatoire, la valeur donnée par la fonction Timer

' Initialisation des 2 variables publiques, leur valeur sera transmise à la fonction génératrice
x1 = 0
x2 = x

End Sub

VI-A-1-c - Fonction Random

À l'instar de la fonction Rnd, elle permet de générer un nombre aléatoire compris entre 0 et 1.

Fonction Random

'********************************************************************************
'************************ Fonction random personnalisée *************************
'********************************************************************************
Function Random() As Single
Dim x As Long ' Variable contenant le nombre pseudoaléatoire

x = (x1 + x2) Mod 10000000 ' Formule type fibonacci modulo la valeur maximale

x1 = x2 ' x1 prend la valeur de x1
x2 = x  ' x2 prend la nouvelle valeur obtenue avec la formule

Random = CLng(x) / 10000000 ' On divise par 10000000 pour avoir un nombre compris entre 0 et 1.

End Function

VI-B - Test de la fonction par la méthode de Monte-Carlo

La méthode de Monte-Carlo consiste à calculer une valeur numérique approchée en utilisant un procédé aléatoire. Elle est particulièrement utilisée pour le calcul de surfaces ou de volumes.

Pour plus de détails, vous pouvez consulter cette page.

VI-B-1 - Détermination de la valeur de Pi

Considérons un cercle de centre 0 et de rayon 1/2, inscrit dans un carré de côté 1.

Le procédé aléatoire va consister à jeter un grand nombre de fois un petit objet dans le carré et à compter à chaque fois que l'objet tombe dans le cercle.

En faisant le rapport du nombre de fois où l'objet est tombé dans le cercle sur le nombre total de lancers, on doit obtenir une approximation du rapport entre la surface du cercle et celle du carré, c'est-à-dire Pi/4.

VI-B-1-a - Fonction Test

Soit un point M de coordonnées (x,y), où -1/2 < x < 1/2 et -1/2 < y < 1/2. On tire aléatoirement les valeurs de x et y avec la fonction Random. Le point M appartient au disque de centre (0,0) de rayon 1/2 si et seulement si x^2 + y^2 <= 1/4. La probabilité que le point M appartienne au disque est donc pi/4.

fonction TestRandom

'********************************************************************************
'*************************** Fonction test de Random ****************************
'********************************************************************************
Public Function TestRandom(n As Long)
' n : nombre de tirages
Dim c As Long ' compteur des tirages dans le cercle
Dim x As Single, y As Single ' coordonnées sur le carré
Dim i As Long ' indice du tirage

' Initialisation du générateur de nombres aléatoires
InitRandom

' Initialisation du compteur
c = 0:

For i = 1 To n

x = (Random - 0.5) ' Génération aléatoire de la valeur pour la coordonnée x
y = (Random - 0.5) ' Génération aléatoire de la valeur pour la coordonnée y

If Sqr(x ^ 2 + y ^ 2) <= 0.5 Then ' Test si le point de coordonnées (x,y) est dans le cercle
c = c + 1 ' Si oui on incrémente le compteur
End If

Next i

TestRandom = (c / n) * 4 ' Renvoie la valeur approximation de Pi (c/n -> Pi/4 d'où : (c / n) * 4 -> Pi)

End Function

À l'exécution, on remarque que la fonction tend vers Pi à mesure que le nombre de tirages augmente. Elle peut donc être considérée comme un générateur de nombres pseudoaléatoires.

VI-C - Note

Étant donné que l'instruction Randomize et la fonction Rnd commencent par une valeur initiale et génèrent des nombres compris dans une plage finie, les résultats peuvent être prévus par toute personne connaissant l'algorithme utilisé pour les créer. L'instruction Randomize et la fonction Rnd ne doivent donc pas être utilisées pour créer des nombres aléatoires qui seront utilisés en chiffrement.

VII - Les bases de données à télécharger

La base jointe au format mdb.

VIII - Remerciements

Je tiens à remercier Laurent Ott, arkham46 et f-leb pour m'avoir conseillé pour la réalisation de cet article, ainsi que Anthony Jorion pour sa relecture.