J'ai lu sur les RNG sur Wikipedia et $RANDOM
fonctionne sur TLDP mais cela n'explique pas vraiment ce résultat:
$ max=$((6*3600))
$ for f in {1..100000}; do echo $(($RANDOM%max/3600)); done | sort | uniq -c
21787 0
22114 1
21933 2
12157 3
10938 4
11071 5
Pourquoi les valeurs ci-dessus environ 2x sont-elles plus enclines à être 0, 1, 2 que 3, 4, 5 mais quand je change le module max, elles sont presque également réparties sur les 10 valeurs?
$ max=$((9*3600))
$ for f in {1..100000}; do echo $(($RANDOM%max/3600)); done | sort | uniq -c
11940 0
11199 1
10898 2
10945 3
11239 4
10928 5
10875 6
10759 7
11217 8
$RANDOM
variable n'utilise pas un bon PRNG en interne.Réponses:
Pour développer le sujet du biais modulo, votre formule est la suivante:
Et dans cette formule,
$RANDOM
est une valeur aléatoire dans la plage 0-32767.Il aide à visualiser comment cela correspond aux valeurs possibles:
Donc, dans votre formule, la probabilité de 0, 1, 2 est le double de 4, 5. Et la probabilité de 3 est légèrement supérieure à 4, 5 également. D'où votre résultat avec 0, 1, 2 comme gagnants et 4, 5 comme perdants.
Lors du passage à
9*3600
, il s'avère que:1-8 ont la même probabilité, mais il y a toujours un léger biais pour 0, et donc 0 était toujours le vainqueur de votre test avec 100'000 itérations.
Pour corriger le biais du modulo, vous devez d'abord simplifier la formule (si vous ne voulez que 0-5, alors le modulo est 6, pas 3600 ou un nombre encore plus fou, cela n'a aucun sens). À elle seule, cette simplification réduira considérablement votre biais (32766 correspond à 0, 32767 à 1, ce qui donne un tout petit biais à ces deux nombres).
Pour éliminer complètement le biais, vous devez relancer (par exemple) quand
$RANDOM
est inférieur à32768 % 6
(éliminer les états qui ne correspondent pas parfaitement à la plage aléatoire disponible).Résultat du test:
L'alternative serait d'utiliser une source aléatoire différente qui n'a pas de biais notable (ordres de grandeur supérieurs à seulement 32 768 valeurs possibles). Mais l'implémentation d'une logique de relance de toute façon ne fait pas de mal (même si cela n'arrive probablement jamais).
la source
Il s'agit d'un biais modulo. Si
RANDOM
est bien construit, chaque valeur entre 0 et 32767 est produite avec une probabilité égale. Lorsque vous utilisez modulo, vous modifiez les probabilités: les probabilités de toutes les valeurs au-dessus du modulo sont ajoutées aux valeurs auxquelles elles correspondent.Dans votre exemple, 6 × 3600 représente environ les deux tiers de la plage de valeurs. Les probabilités du tiers supérieur s'ajoutent donc à celles du tiers inférieur, ce qui signifie que des valeurs de 0 à 2 (environ) sont deux fois plus susceptibles d'être produites que des valeurs de 3 à 5. 9 × 3600 est près de 32767, donc le le biais modulo est beaucoup plus petit et n'affecte que les valeurs de 32400 à 32767.
Pour répondre à votre question principale, au moins dans Bash, la séquence aléatoire est entièrement prévisible si vous connaissez la graine. Voir
intrand32
dansvariables.c
.la source