Première supposition... choisissez un nombre aléatoire entre 1 et 2. 2**size
trouver le logarithme de base 2 de cette valeur, et choisir le nombre d'éléments à partir de la fin.
Pardonnez mes horribles compétences en rubis.
return a[-((Math.log(rand(2**size-1)+1) / Math.log(2)).floor) - 1]
si rand
renvoie 0, le dernier élément doit être choisi. 1 ou 2, l'avant-dernier. 3, 4, 5 ou 6, le troisième en partant de la fin. Etc. En supposant une distribution égale des nombres aléatoires, chaque élément a deux fois plus de chances d'être choisi que celui qui le suit.
Edit : En fait, il semble qu'il y ait une log2
de sorte que nous n'avons pas à faire le truc de log/log(2).
return a[-(Math.log2(rand(2**size - 1)+1).floor) - 1]
Vous pouvez peut-être vous débarrasser complètement de ces appels de journal comme
return a[-((rand(2**size-1)+1).to_s(2).length)]
Mais vous créez un supplément String
. Je ne sais pas si c'est mieux que des mathématiques compliquées :)
Edit : En fait, si vous optez pour la méthode des chaînes, vous pouvez vous débarrasser complètement des +1 et -1. Cela rendrait les probabilités plus précises, puisque les deux derniers éléments devraient avoir une chance égale d'être choisis. (Si l'avant-dernière valeur n'est pas choisie, la dernière valeur le serait toujours).
Edit : Nous pourrions également transformer le **
en un décalage de bits, ce qui devrait être un peu plus rapide (à moins que Ruby ne soit assez intelligent pour le faire déjà).
return a[-(rand(1<<size).to_s(2).length)]