在Lua中生成均匀随机数

28
我正在Lua中编写一个马尔可夫链的程序,其中一个要素是需要我均匀生成随机数。下面是一个简化的例子,用来说明我的问题:
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))

我的问题是,当我多次重新运行这个程序时,会生成完全相同的随机数,导致示例函数选择相同的数组元素。然而,如果我在单个程序中多次重复打印行,包含多次对示例函数的调用,我会得到合适的随机结果。
这并不是我的意图,因为一个合适的马尔可夫伪随机文本生成器应该能够多次运行相同的程序,并每次输出不同的伪随机文本。我尝试使用math.randomseed(os.time())来重置种子,这样随机数分布就不再均匀。我的目标是能够重新运行上述程序,并每次接收到一个随机选择的数字。

2
仅需对生成器进行一次种子操作。 - lhf
1
非常感谢您的帮助。奇怪的是,在生成器进行种子处理之后(仅一次!),第一次调用math.random总是返回相同的值。然而,在此之后,所有随后的调用都会返回我所期望的随机性。在我开始使用math.random返回的数字之前,我只需要进行一个“垃圾”调用。无论如何,再次感谢。 - Starfish_Prime
这是一些C标准库实现中Mersenne旋转算法的预期输出:第一个值会根据种子差异略微漂移,然后第二个值会漂移得更多,依此类推。 - Stuart P. Bentley
4个回答

29

在使用 math.random() 之前,您需要运行 math.randomseed() 一次,如下所示:

math.randomseed(os.time())

根据您的评论,您看到第一个数字仍然是相同的。这是由于某些平台中随机生成器的实现方式引起的。

解决方法是在实际使用随机数之前弹出一些随机数字:

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

注意标准C库中的random()函数通常不是完全均匀的随机数生成器,如果您的平台提供了更好的随机数生成器,则最好使用它。

参考:Lua数学库教程


13

在Lua中使用的标准C随机数生成器不能保证模拟的好坏。"Markov chain"这个词表明您可能需要一个更好的生成器。这是一个广泛用于蒙特卡罗计算的生成器:

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

它生成介于0和1之间的数字,因此r = math.floor(rand()*10) + 1将适用于您的示例。(这是具有周期2^38、乘数5^17和模数2^40的乘法随机数生成器,原始的Pascal代码来自http://osmf.sscc.ru/~smp/)


1
然而,这将始终产生相同的数字序列。不清楚如何在不降低周期的情况下“种植”过程(例如通过更改X1X2的初始值) 。 - Witiko
要获得不同的序列,您需要将X1和X2设置为不同的数字。 0 <= X1 <= 2^20-1, 1 <= X2 <= 2^20-1(必须是奇数!) 此外,该算法可以进行大量优化,特别是使用64位无符号整数。 - GrayFace
基本上,在LuaJIT中,rand()归结为以下内容:X1 = X1762939453125ull; return tonumber(X1)(2.0^-64)。初始X1为0ull + (Seed*2 + 1) * 2^24,其中0 <= Seed <= 2^39-1。 - GrayFace

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

总是生成新的随机数。改变种子值将确保随机性。不要使用os.time(),因为它是历元时间,并且在一秒后会更改,但os.clock()在任何接近的实例中不会具有相同的值。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接