bonjour,
je vous propose une petite fonction qui calcule l'inverse de la loi normale, standard ou non, c'est à dire donne Z pour une probabilité donnée.
si vous référencez Excel dans Access, vous pouvez comparer les résultats via cette fonction de test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 Option Compare Database Option Explicit Private Const gcUMax As Double = 55.5 Private Const gcInvNCRMax As Single = 99 '--------------------------------------------------------------------------------------- ' Procédure : NormaleInverse [Function] ' Retour : Single ' Version : 1.01 ' Création/Maj : Le samedi 21 juillet 2007 à 11:36 ' Objet : Détermine la variable Z d'une distribution normale en fonction de ' : sa probabilité, de la moyenne et de l'écart-type de la distribution ' Historique : '--------------------------------------------------------------------------------------- Public Function NormaleInverse(ByVal fProb As Single, ByVal dMean As Double, _ ByVal dEcartType As Double) As Single NormaleInverse = NormaleStdInverse(fProb) If NormaleInverse > -gcInvNCRMax And NormaleInverse < gcInvNCRMax Then NormaleInverse = (NormaleInverse * dEcartType) + dMean End If End Function '--------------------------------------------------------------------------------------- ' Procédure : NormaleStdInverse [Function] ' Retour : Single ' Version : 1.01 ' Création/Maj : Le samedi 21 juillet 2007 à 11:37 ' Objet : Détermine la variable Z d'une distribution normale centrée réduite ' : en fonction de sa probabilité ' : Renvoie 0 si p <= 0 et 99 si p >= 1 ' Historique : '--------------------------------------------------------------------------------------- Public Function NormaleStdInverse(ByVal fProb As Single) As Single Const cdEPSILON As Double = 0.0000001 Const ciMaxIter As Integer = 50 Dim dMax As Double, dMin As Double, dCalcZ As Double Dim i As Integer Dim bSign As Boolean If fProb <= 0 Then NormaleStdInverse = -gcInvNCRMax ElseIf fProb >= 1 Then NormaleStdInverse = gcInvNCRMax Else dMin = -Sqr(gcUMax) If fProb > 0.5 Then fProb = 1 - fProb bSign = True End If While Abs(dMax - dMin) >= cdEPSILON And i < ciMaxIter dCalcZ = (dMax + dMin) * 0.5 If AireZ(dCalcZ) < fProb Then dMin = dCalcZ Else dMax = dCalcZ End If i = i + 1 Wend NormaleStdInverse = IIf(bSign, -dCalcZ, dCalcZ) End If End Function '--------------------------------------------------------------------------------------- ' Procédure : AireZ [Function] ' Retour : Single ' Version : 1.0 ' Création/Maj : Le samedi 21 juillet 2007 à 11:38 ' Objet : Calcul l'aire sous la courbe de la loi normale centrée réduite ' : en fonction d'une variable Z. ' : La probabilité unilatérale est : Prob = 1 - AireZ(Z) ' Historique : '--------------------------------------------------------------------------------------- Public Function AireZ(z As Double) As Single Dim f As Double, u As Double, s As Double, t As Double, s1 As Double u = z * z If u > gcUMax Then AireZ = IIf(z > 0, 1, 0) Else s1 = 1 'Pour passer le test while initial t = 1 f = 3 While s <> s1 s1 = s s = s + t t = t * u / f f = f + 2 Wend AireZ = z * s / ((8 * Atn(1) * Exp(u)) ^ 0.5) + 0.5 End If End Function
Résultats :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 Public Function TestLoiNormaleInverse() Dim dExcel As Double, dMaxErr As Double, dMaxDiff As Double Dim dTmpDiff As Double, dDiffErr As Double Dim v As Single, fAccess As Single, fMaxDiffAt As Single, fMaxErrAt As Single Dim l As Long Dim t0 As Single v = 0.000001 Do While v <= 1 And l < 100000 dExcel = WorksheetFunction.NormSInv(v) fAccess = NormaleStdInverse(v) dTmpDiff = Abs(dExcel - fAccess) If dTmpDiff > dMaxDiff Then dMaxDiff = dTmpDiff fMaxDiffAt = v End If If (dTmpDiff / dExcel) > dMaxErr Then dMaxErr = dTmpDiff / dExcel fMaxErrAt = v dDiffErr = dTmpDiff End If l = l + 1 v = v + 0.00001 If l Mod 1000 = 0 Then Debug.Print "Boucle n°" & l & " Val = " & v DoEvents Loop Debug.Print "Max Diff. :" & Format(dMaxDiff, "0.00E+00") & " pour v=" & fMaxDiffAt Debug.Print "Max Err. relative % :" & Format(dMaxErr, "0.0000%") & _ " pour v=" & fMaxErrAt & " Différence :" & dDiffErr End Function
Pourquoi ne pas utiliser directement Excel en référence ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Max Diff. :2,28E-07 pour v=0,000031 Max Err. relative % :1,2035% pour v=0,5000017 Différence :5,21464904139617E-08
1) Indépendance par rapport à Excel
2) Excel est 10 fois plus lent d'après des tests
Inconvénients ?
1) Précision limitée au type Single contrairement à Excel (Double)
2) Autres ? Vous allez me le dire !
cordialement,
Philippe
Partager