la question de la formule du Loto nous a amené
à la question nettement plus intéressante du
calcul général de C(n,p) avec :
p n!
C = -------------
n (n-p)! . p!
VB ne disposant pas de la fonction factorielle,
on peut exprimer C(n,p) comme :
p n * (n-1) * (n-2) * ... * (n-p+1)
C = -----------------------------------
n p * (p-1) * (p-2) * ... * 2
Il est évident que le calcul du nominateur et/ou du
dénominateur va très vite être plus grand qu'un Long.
Exemple : le calcul de C(49,6) =
(49*48*47*46*45*44) / (6*5*4*3*2) entraine un dépassement
de capacité au niveau du numérateur car le résultat est trop
grand pour un Long (ici il vaut 10.068.347.520 alors que la
limite d'un Long est 2.147.483.647).
Pourtant, le résultat (qui vaut 13.983.816) est tout petit
en comparaison et tient sans problème dans un Long.
Il faut donc être un peu malin et essayer de contraindre
le numérateur à être le plus petit possible.
Je vous propose la petite fonction suivante qui permet de calculer
C(n,p) de façon intelligente. En pratique, elle pourra calculer tous
les C(n,p) dont le résultat final tient dans un Long.
Elle utilise la fonction PGCD() dont un exemple d'implémentation
est donné dans la FAQ : http://faq.vb.free.fr/index.php?question=182
Voici :
Public Function Cnp(ByVal n As Long, ByVal p As Long) As Long
Dim NumLow As Long
Dim i As Long
Dim j As Long
Dim r As Long
Dim t() As Long
Dim tempNum As Long
Dim Num As Long
Dim pp As Long
Dim must_stop As Boolean
NumLow = n - p + 1
ReDim t(p)
For i = 2 To p
t(i - 1) = i
Next i
Num = 1
For i = n To NumLow Step -1
tempNum = i
Do
must_stop = True
For j = 1 To p - 1
pp = PGCD(tempNum, t(j))
If pp > 1 Then
tempNum = tempNum / pp
t(j) = t(j) / pp
must_stop = False
End If
Next j
Loop While (Not must_stop) And (tempNum <> 1)
Num = Num * tempNum
Next i
For i = 1 To p - 1
Num = Num / t(i)
Next i
Cnp = Num
End Function
Private Function PGCD(ByVal n1 As Long, ByVal n2 As Long) As Long
If n2 = 0 Then
PGCD = n1
Else
PGCD = PGCD(n2, n1 Mod n2)
End If
End Function
' --------------------------------------------------
Note : Non, utiliser des Double ne serait *PAS* une
bonne(tm) solution, pas plus qu'utiliser un type Currency...
Pour ce qui est du code, j'ai mes habitudes et je ne ferais sûrement pas comme toi. J'ai juste besoin de connaître mieux ta méthode,
Certes, mais il il s'agit d'une simple fonction que tu peux appeler à ta guise :
Dim n as long, p as long, V as Long
n = 49 p = 6
V = Cnp(n, p) ...
puisque tu dis qu'elle résout les problèmes de dépassement de capacité
Bon, la "méthode" en 2 mots.
Tout repose sur l'idée de simplification ou réduction d'une fraction. p Soit A = --- q a * p' Si on peut écrire A sous la forme A = ------- , alors on peut "simplifier" a * q'
la fraction par a et donc A = p' / q'.
Si en plus "a" est le plus grand nombre divisant à la fois p et q, alors on a obtenu la meilleure simplification possible.
35 Exemple A = ----- 28
Le plus grand nombre qui divise à la fois 35 et 28 est 7. On nomme un tel nombre le PGCD (Plus Grand Commun Dénominateur) Donc :
A = (7 * 5) / (4 * 7) se simplifie par 7 et devient A = 5/4
Ce que fait mon programme, c'est de parcourir les éléments du numérateur et de chercher le PGCD de ce nombre avec chacun des termes du dénominateur. Dès qu'on en trouve un, on simplifie les termes par une simple division. On répète ce processus itérativement jusqu'à ce que tous les termes du numérateur ait été réduit au maximum. Alors seulement on effectue la multiplication finale, qui bien sur met en jeu des nombres bien plus petits, évitant par là même tout dépassement de capacité (ou du moins reculant l'apparition de cette situation autant se faire que peut).
Pour ce qui est du code, j'ai mes habitudes et je
ne ferais sûrement pas comme toi. J'ai juste besoin de connaître
mieux ta méthode,
Certes, mais il il s'agit d'une simple fonction que tu peux appeler
à ta guise :
Dim n as long, p as long, V as Long
n = 49
p = 6
V = Cnp(n, p)
...
puisque tu dis qu'elle résout les problèmes de
dépassement de capacité
Bon, la "méthode" en 2 mots.
Tout repose sur l'idée de simplification ou réduction d'une fraction.
p
Soit A = ---
q
a * p'
Si on peut écrire A sous la forme A = ------- , alors on peut "simplifier"
a * q'
la fraction par a et donc A = p' / q'.
Si en plus "a" est le plus grand nombre divisant à la fois p et q, alors
on a obtenu la meilleure simplification possible.
35
Exemple A = -----
28
Le plus grand nombre qui divise à la fois 35 et 28 est 7.
On nomme un tel nombre le PGCD (Plus Grand Commun Dénominateur)
Donc :
A = (7 * 5) / (4 * 7) se simplifie par 7 et devient A = 5/4
Ce que fait mon programme, c'est de parcourir les éléments du numérateur et
de chercher le PGCD de ce nombre avec chacun des termes du dénominateur. Dès
qu'on
en trouve un, on simplifie les termes par une simple division.
On répète ce processus itérativement jusqu'à ce que tous les termes du
numérateur
ait été réduit au maximum. Alors seulement on effectue la multiplication
finale,
qui bien sur met en jeu des nombres bien plus petits, évitant par là même
tout
dépassement de capacité (ou du moins reculant l'apparition de cette
situation
autant se faire que peut).
Pour ce qui est du code, j'ai mes habitudes et je ne ferais sûrement pas comme toi. J'ai juste besoin de connaître mieux ta méthode,
Certes, mais il il s'agit d'une simple fonction que tu peux appeler à ta guise :
Dim n as long, p as long, V as Long
n = 49 p = 6
V = Cnp(n, p) ...
puisque tu dis qu'elle résout les problèmes de dépassement de capacité
Bon, la "méthode" en 2 mots.
Tout repose sur l'idée de simplification ou réduction d'une fraction. p Soit A = --- q a * p' Si on peut écrire A sous la forme A = ------- , alors on peut "simplifier" a * q'
la fraction par a et donc A = p' / q'.
Si en plus "a" est le plus grand nombre divisant à la fois p et q, alors on a obtenu la meilleure simplification possible.
35 Exemple A = ----- 28
Le plus grand nombre qui divise à la fois 35 et 28 est 7. On nomme un tel nombre le PGCD (Plus Grand Commun Dénominateur) Donc :
A = (7 * 5) / (4 * 7) se simplifie par 7 et devient A = 5/4
Ce que fait mon programme, c'est de parcourir les éléments du numérateur et de chercher le PGCD de ce nombre avec chacun des termes du dénominateur. Dès qu'on en trouve un, on simplifie les termes par une simple division. On répète ce processus itérativement jusqu'à ce que tous les termes du numérateur ait été réduit au maximum. Alors seulement on effectue la multiplication finale, qui bien sur met en jeu des nombres bien plus petits, évitant par là même tout dépassement de capacité (ou du moins reculant l'apparition de cette situation autant se faire que peut).