XL 2013 crer une liste de nombres aleatoires entre un min et un max avec une fonction VBA méthode particulière

patricktoulon

XLDnaute Barbatruc
Bonsoir à tous
c'est juste pour le fun
perso pour créer une liste de nombres aléatoires je préfère mélanger une liste ordonné(dans l'ordre au départ)
on a la garantie de non doublons et c'est largement plus rapide
sauf que là l'exercice est encore plus intéressant
je demarre avec une liste (un array vide(sans valeur)
alors pour faire de 1 à max ca va ,mais pour faire de min à max ca devient compliqué avec cette méthode tout du moins sans transformé un code très simple à la base en en centrale nucléaire

voici la méthode avec un array vide sans doublons et de 1 à max
VB:
Function randomListNumber(maxi)
   Dim i&, X&, temp
   Randomize
    ReDim t(1 To maxi)
    For i = 1 To maxi
        If t(i) = "" Then t(i) = i
        temp = t(i)
        X = 1 + Int((Rnd * (maxi - 1)))
        If t(X) = "" Then t(X) = X
        t(i) = t(X)
        t(X) = temp
    Next
    randomListNumber = t
End Function

Sub test()
    MsgBox Join(randomListNumber(30), vbCrLf)
End Sub
 

Dudu2

XLDnaute Barbatruc
Même punition en Office 2016.

1697664138844.png
1697664059106.png
 

Dranreb

XLDnaute Barbatruc
voici la méthode avec un array vide sans doublons et de 1 à max
La mienne :
VB:
Sub CalcTAléa(T() As Long, ByVal Max As Long, ByVal Gr As Double)
   Dim N As Long, P As Long
   If Gr <> 0 Then Rnd -1: Randomize Gr Else randomize
   ReDim T(1 To Max)
   T(1) = 1
   For N = 2 To Max
      P = Int(N * Rnd) + 1
      If P < N Then T(N) = T(P)
      T(P) = N: Next N
   End Sub
Je pense qu'elle aboutit à une répartition uniforme (à vérifier ?) comme le mélange de Fisher-Yates mais, c'est vrai, sans nécessiter de boucle de remplissage ordonné préalable. Je vais peut être l'adopter dans ma classe ListeAléat.
Pour un remplissage à partir d'un Min autre que 1, l'affecter à la place de 1 au 1er élément puis dans la boucle l'incrémenter et l'affecter à T(P) au lieu d'y affecter N.
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
Bonjour @Dranreb, @patricktoulon,
Cet algorithme est similaire à celui de @patricktoulon qui introduit l'indice dans les tirages.

Alors je me suis intéressé à l'algorithme de @patricktoulon. Je n'avais pas relancé pour ne pas créer de discussions supplémentaires mais ton post m'incite à le faire et j'ai donc étendu le test au tien.

Certes, dans les 2 cas, il y a un certain niveau de randomisation, mais selon les tirages et la répartition entre le nombre de valeurs déterminées par l'indice (Nbi dans le code ci-dessous) et le nombre de valeurs déterminées par le tirage au sort (Nbx dans le code ci-dessous), il y a de nombreux cas où, sur 30 tirages de 10 valeurs, les listes générées sont identiques. Et ça ce n'est pas normal dans un tirage aléatoire de 10! possibilités.

Par exemple dans ton algorithmes, pour les valeurs possibles des Nbi = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Les valeurs Nbi = 1, 5, 6, 7, 8, 9, 10 (9 est rare, 10 très rare, donc le test est plus long en CPU), des colonnes, parfois très nombreuses, voire toutes pour 10 évidemment, parmi seulement 30 tirages, sont identiques.

Alors certes, je fais ce test pour une configuration particulière de Nbi, mais le problème c'est que des Nbi il n'y en a que 10 dans l'exemple donc on retombe fréquemment sur un Nbi donné dont il faudrait calculer la probabilité pour être plus précis.

L'algorithme de @patricktoulon présente les mêmes problèmes à une échelle moindre. Il n'a pas ton test If P < N.
 

Pièces jointes

  • Classeur1.xlsm
    33.4 KB · Affichages: 3
Dernière édition:

patricktoulon

XLDnaute Barbatruc
bonjour @Dranreb

je l'ai adapté avec un min/max et nombres d'item
ici dans cet exemple on démarre de -5 jusqu'a 30 et on prend 20 valeurs dans cet intervalle
VB:
Sub test2()
    MsgBox Join(CalcTAléa2(-5, 30, 20), vbCrLf)
End Sub

Function CalcTAléa2(ByVal min As Long, ByVal Maxi As Long, ByVal nbitem As Long)
    Dim N As Long, P As Long, t()
    Randomize
    ReDim Preserve t(min To Maxi)
    t(min) = min
    For N = 1 To Maxi - min
        P = Int((N * Rnd))
        If P + min < N + min Then t(N + min) = t(P + min)
        t(P + min) = N + min
        Debug.Print Join(t, ",") & "--->" & N & "---->" & P
    Next N
    ReDim Preserve t(min To min + nbitem)
    CalcTAléa2 = t
End Function

on peut même ajouter une sorti une fois le nombre d'item obtenu
juste avant le next
VB:
 If N - min = nbitem Then Exit For
 
Dernière édition:

dysorthographie

XLDnaute Accro
Bonjour,
Le redom est obtenu par le déroulement d'un algorithme qui lui est toujours le même, il n'y a rien d'aléatoire !

Pas étonnant qu'il produise le même résultat a plusieurs reprises.

La seule chose qu'il est difficile de mettriser c'est l'heure à la qu'elle on exécute la macro.
Code:
Randomize Timer
 

patricktoulon

XLDnaute Barbatruc
re
@Dudu2 le probleme que tu decrit vient d'une simple chose
@dranred random un nombre entre la position dans la boucle et plus
moi je random un nombre entre debut et fin

je suis d'accords avec robert la fonction randomize et particulière
et la fonction RND n'est pas si aléatoire que ça en fait

en fait plus l’écart entre le min et le max est grand plus la fonction RND donnera l’illusion d'une sélection aléatoire du nombre
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
tu n'a qu'a tester ca pour comprendre le defaut (si on peut appeler ca un defaut)
et on vois bien qu'avec le model de @Dranreb plus on va vers le 10 plus l'ecart en l'index de boucle et le nombre aléatoire obtenu est grand
tandis qu'avec mon model c'est un peu plus désordonné dès le depart
Code:
Sub testq()
Randomize Timer
texte = "version @dranreb" & vbCrLf
For N = 1 To 10
texte = texte & N & "--->" & Int(N * Rnd) + 1 & vbCrLf
Next

texte = texte & vbCrLf & "version patrick" & vbCrLf
For N = 1 To 10
texte = texte & N & "--->" & Int(1 + (Rnd * (10 - 1))) + 1 & vbCrLf
Next
MsgBox texte
End Sub
 

Dudu2

XLDnaute Barbatruc
En fait il faudrait un spécialiste des probabilités de haut niveau pour démonter que oui ou non c'est 100% aléatoire. Je n'ai que des doutes d'abord intuitifs puis exprimés dans le fichier de test ci-dessus qui n'est peut-être pas du tout représentatif. Donc voilà... Je savais qu'il fallait pas relancer 😂.
 

patricktoulon

XLDnaute Barbatruc
conclusion
plus le
En fait il faudrait un spécialiste des probabilités de haut niveau pour démonter que oui ou non c'est 100% aléatoire. Je n'ai que des doutes d'abord intuitifs puis exprimés dans le fichier de test ci-dessus qui n'est peut-être pas du tout représentatif. Donc voilà... Je savais qu'il fallait pas relancer 😂.
re
a ben je peux te le dire tout de suite non ce n'est pas aléatoire
RND c'est un algo puissant mais qui a ces limites
et ses limites sont justement l’écart entre le min et le max demandé
c'est simple à comprendre
dans une boucle de 1 à 10
entre 1 et 10 tu a plus de chance de tomber sur 1 par exemple
que entre 1 et 100
c'est tout bête en fait
mais là ou mon algo et tout les dérivé qui ont suivit dépasse ça ,c'est que le nombre aléatoire finalement passe au second plan
c'est a dire que c'est un mélange donc tout les item sont mélangés dans la boucle
et donc des items sont parfois déménagé plusieurs fois
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
@patricktoulon, mes doutes ne sont pas liés au Rnd() mais au fait qu'on introduise l'indice dans les valeurs et qu'on randomise sur des permutations en 1 seule boucle.
ben il faut bien gérer les doublons ma fois :oops:
c'est là qu'il est le plus !! de cet algo
et pour te la faire courte
tout autres principes impliqueraient forcement un nombre de tours de boucle plus important que le nombre d'item voulu car il faudrait alors gérer le passe d'un doublon ou une autre boucle

c'est simple un doublon trouvé dans la boucle ne peut pas être mauvais avec mon algo

c'est super simple à comprendre en fait
en fait et je l'ai dis dès le départ c'est un mélange d'une liste ordonnée
ben forcément on va randomiser sur les indices(index)et non sur les valeurs
 
Dernière édition:

Discussions similaires

Statistiques des forums

Discussions
315 127
Messages
2 116 538
Membres
112 774
dernier inscrit
Foudil59