Random Lua中均匀随机数的生成
我正在用Lua编写一个马尔可夫链,其中一个元素要求我统一生成随机数。下面是一个简单的例子来说明我的问题:Random Lua中均匀随机数的生成,random,lua,random-seed,Random,Lua,Random Seed,我正在用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)) 我的问题是,当我多次重新运行这个程序(ma
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))
我的问题是,当我多次重新运行这个程序(mash F5)时,会生成完全相同的随机数,导致示例函数选择完全相同的数组元素。但是,如果通过多次重复末尾的打印行,在单个程序中包含对示例函数的多次调用,则会得到合适的随机结果
这不是我的意图,因为一个合适的马尔可夫伪随机文本生成器应该能够多次使用相同的输入运行相同的程序,并且每次都输出不同的伪随机文本。我尝试使用
math.randomseed(os.time())
重置种子,这使得随机数分布不再均匀。我的目标是能够重新运行上述程序并每次接收随机选择的数字。在使用math.random()
之前,您需要运行math.random()
一次,如下所示:
math.randomseed(os.time())
从你的评论来看,你看到的第一个数字仍然是一样的。这是由于在某些平台上实现了随机生成器造成的
解决方案是先弹出一些随机数,然后再将其用于实数:
math.randomseed(os.time())
math.random(); math.random(); math.random()
请注意,标准C库random()
通常不是均匀随机的,更好的解决方案是使用更好的随机生成器(如果您的平台提供)
参考资料:Lua中使用的标准C随机数生成器不适合模拟。“马尔可夫链”这个词暗示你可能需要一个更好的。这是一个广泛用于蒙特卡罗计算的生成器:
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代码为)
总是产生新的随机数。更改种子值将确保随机性,不要遵循os.time()
因为它的纪元时间和一秒钟后的更改,但是os.clock()
在任何接近的实例中都没有相同的值。干杯 有一个Luaossl库解决方案:()
为发电机设定一次种子。非常感谢您的帮助。奇怪的是,在对生成器进行种子设定(一次!)之后,对math.random的第一次调用总是返回相同的值。在那之后,尽管所有后续调用都返回我所寻找的随机性。在我开始使用math.random返回的数字之前,我只有一个“垃圾”电话。无论如何,再次感谢。这是在一些C标准库实现中实现的Mersenne twister的预期输出:第一个值将根据种子的差异稍微漂移,然后第二个值将漂移更多,依此类推。但是,这可能的重复将始终产生相同的数字序列。不清楚如何在不降低周期的情况下“播种”过程(例如,通过更改X1
和X2
的初始值)。要获得不同的序列,需要将X1和X2设置为不同的数字。0基本上,在LuaJIT rand()中归结为:X1=X1*762939453125ull;返回到编号(X1)*(2.0^-64)。初始X1为0ull+(种子*2+1)*2^24,其中0
math.randomseed(os.clock()*100000000000)
for i=1,3 do
math.random(10000, 65000)
end
local rand = require "openssl.rand"
local randominteger
if rand.ready() then -- rand has been properly seeded
-- Returns a cryptographically strong uniform random integer in the interval [0, n−1].
randominteger = rand.uniform(99) + 1 -- randomizes an integer from range 1 to 100
end