Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

formule du lote et Combinaisons

11 réponses
Avatar
Jean-marc
Hello à tous,

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...

Bonne lecture et bonne soirée !

--
Jean-marc Noury (jean_marc_n2)
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr

1 réponse

1 2
Avatar
Jean-marc
fraction wrote:

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).


--
Jean-marc Noury (jean_marc_n2)
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;
1 2