web-dev-qa-db-fra.com

Génération de nombres aléatoires uniformes dans Lua

Je travaille sur la programmation d'une chaîne de Markov dans Lua, et un élément de cela nécessite que je génère uniformément des nombres aléatoires. Voici un exemple simplifié pour illustrer ma question:

example = function(x)
    local r = math.random(1,10)
    print(r)
    return x[r]
end

exampleArray = {"a","b","c","d","e","f","g","h","i","j"}

print(example(exampleArray))

Mon problème est que lorsque je réexécute ce programme plusieurs fois (mash F5) le même nombre aléatoire exact est généré, ce qui permet à la fonction d'exemple de sélectionner exactement le même élément de tableau. Cependant, si j'inclus de nombreux appels à la fonction d'exemple dans le programme unique en répétant la ligne d'impression à la fin plusieurs fois, j'obtiens des résultats aléatoires appropriés.

Ce n'est pas mon intention car un générateur de texte pseudo-aléatoire de Markov devrait pouvoir exécuter le même programme plusieurs fois avec les mêmes entrées et produire à chaque fois un texte pseudo-aléatoire différent. J'ai essayé de réinitialiser la graine en utilisant math.randomseed(os.time()) et cela fait que la distribution de nombres aléatoires n'est plus uniforme. Mon objectif est de pouvoir relancer le programme ci-dessus et recevoir un numéro sélectionné au hasard à chaque fois.

15
Starfish_Prime

Vous devez exécuter math.randomseed() une fois avant d'utiliser math.random(), comme ceci:

math.randomseed(os.time())

D'après votre commentaire que vous avez vu le premier numéro est toujours le même. Cela est dû à l'implémentation d'un générateur aléatoire dans certaines plates-formes.

La solution consiste à faire apparaître des nombres aléatoires avant de les utiliser pour de vrai:

math.randomseed(os.time())
math.random(); math.random(); math.random()

Notez que la bibliothèque C standard random() n'est généralement pas aussi uniformément aléatoire, une meilleure solution consiste à utiliser un meilleur générateur aléatoire si votre plateforme en fournit un.

Référence: Lua Math Library

10
Yu Hao

Le générateur de nombres aléatoires C standard utilisé dans Lua n'est pas garanti pour être bon pour la simulation. Les mots "chaîne de Markov" suggèrent que vous pourriez en avoir besoin d'un meilleur. Voici un générateur largement utilisé pour les calculs de Monte-Carlo:

local A1, A2 = 727595, 798405  -- 5^17=D20*A1+A2
local D20, D40 = 1048576, 1099511627776  -- 2^20, 2^40
local X1, X2 = 0, 1
function Rand()
    local U = X2*A2
    local V = (X1*A2 + X2*A1) % D20
    V = (V*D20 + U) % D40
    X1 = math.floor(V/D20)
    X2 = V - X1*D20
    return V/D40
end

Il génère un nombre compris entre 0 et 1, donc r = math.floor(Rand()*10) + 1 irait dans votre exemple. (C'est un générateur de nombres aléatoires multiplicatif avec période 2 ^ 38, multiplicateur 5 ^ 17 et modulo 2 ^ 40, code Pascal original par http://osmf.sscc.ru/~smp/ )

11
GrayFace
math.randomseed(os.clock()*100000000000)
for i=1,3 do
    math.random(10000, 65000)
end

Toujours un nouveau nombre aléatoire. La modification de la valeur de départ assurera le caractère aléatoire, ne suit pas os.time() car son heure d'époque et change après une seconde mais os.clock() n'a pas la même valeur dans une instance proche. À votre santé!

5
daemonsl