【问题标题】:Generating uniform random numbers in Lua在 Lua 中生成统一的随机数
【发布时间】:2013-12-07 22:21:02
【问题描述】:

我正在用 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))

我的问题是,当我多次重新运行该程序(混搭 F5)时,会生成完全相同的随机数,导致示例函数选择完全相同的数组元素。但是,如果我通过在末尾重复打印行多次在单个程序中包含对示例函数的多次调用,我会得到合适的随机结果。

这不是我的意图,因为正确的马尔可夫伪随机文本生成器应该能够多次运行具有相同输入的相同程序并每次输出不同的伪随机文本。我尝试使用math.randomseed(os.time()) 重置种子,这使得随机数分布不再均匀。我的目标是能够重新运行上面的程序,每次都能收到一个随机选择的数字。

【问题讨论】:

  • 种子生成器一次
  • 非常感谢您的帮助。奇怪的是在为生成器播种后(一次!)第一次调用 math.random 总是返回相同的值。在那之后,尽管所有后续调用都返回了我正在寻找的随机性。在我开始使用 math.random 返回的数字之前,我只有一个“垃圾”电话。无论如何,再次感谢。
  • 这是在某些 C 标准库实现中实现的 Mersenne twister 的预期输出:第一个值会根据种子的差异略有漂移,然后第二个值会漂移得更多,依此类推。

标签: random lua random-seed


【解决方案1】:

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

math.randomseed(os.time())

根据您的评论,您看到的第一个数字仍然相同。这是由于在某些平台上实现了随机生成器造成的。

解决方案是在真正使用它们之前弹出一些随机数:

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

请注意,标准 C 库 random() 通常不是那么均匀随机,如果您的平台提供更好的随机生成器,更好的解决方案是使用随机生成器。

参考:Lua Math Library

【讨论】:

    【解决方案2】:

    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,http://osmf.sscc.ru/~smp/ 的原始 Pascal 代码)

    【讨论】:

    • 然而,这将始终产生相同的数字序列。目前尚不清楚如何在不降低周期的情况下“播种”该过程(例如,通过更改 X1X2 的初始值)。
    • 要获得不同的序列,您需要将 X1 和 X2 设置为不同的数字。 0
    • 基本上,在 LuaJIT rand() 中归结为:X1 = X1*762939453125ull;返回数字(X1)*(2.0^-64)。初始 X1 为 0ull + (Seed*2 + 1) * 2^24,其中 0
    【解决方案3】:
    math.randomseed(os.clock()*100000000000)
    for i=1,3 do
        math.random(10000, 65000)
    end
    

    总是产生新的随机数。更改种子值将确保随机性。不要关注os.time(),因为它是纪元时间,并且在一秒后发生变化,但os.clock() 在任何关闭实例中都不会具有相同的值。

    【讨论】:

      【解决方案4】:

      这里有 Luaossl 库解决方案:(https://github.com/wahern/luaossl)

      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
      

      http://25thandclement.com/~william/projects/luaossl.pdf

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-18
        • 2014-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-15
        相关资源
        最近更新 更多