Random LUA4.0随机数发生器

Random LUA4.0随机数发生器,random,lua,prng,Random,Lua,Prng,我无法访问Lua4.0中的random,所以我需要使用自己的随机数生成器。或者更确切地说,我必须推出另一个,因为我几年前实施的一个现在让我失望了。也就是说,我注意到重复的值是不好的 有没有用Lua编写的我可以使用的建议或示例?仅供参考,这是我到目前为止一直在使用的: seedobja = 1103515245 seedobjc = 12345 seedobjm = 4294967295 --0x100000000 function srandom(seedobj, fVal1, fVal2)

我无法访问Lua4.0中的random,所以我需要使用自己的随机数生成器。或者更确切地说,我必须推出另一个,因为我几年前实施的一个现在让我失望了。也就是说,我注意到重复的值是不好的

有没有用Lua编写的我可以使用的建议或示例?仅供参考,这是我到目前为止一直在使用的:

seedobja = 1103515245
seedobjc = 12345
seedobjm = 4294967295 --0x100000000

function srandom(seedobj, fVal1, fVal2)
    seedobj[1] = mod(seedobj[1] * seedobja + seedobjc, seedobjm)
    local temp_rand = seedobj[1] / (seedobjm - 1)
    if (fVal2) then
        return floor(fVal1 + 0.5 + temp_rand * (fVal2 - fVal1))
    elseif (fVal1) then
        return floor(temp_rand * fVal1) + 1
    else
        return temp_rand
    end
end
[编辑]


后来编辑被删除。

我没有安装Lua4.0,也从未使用过它,因此下面的代码可能需要一些调整

这是在Lua5.1上工作的东西。这是对用C编写的Park和Miller生成器实现的粗略修改,使用32位整数。我试图更接近我从您的代码片段中猜到的4.0语法。测试它,看看它的周期是否适合你的需要。原始版本的周期约为2e9,但转换为浮点运算可能会破坏某些东西这些生成器是非常微妙的事情

local mod = math.fmod
local floor = math.floor

local B = 2^31
-- rough adaptation of Park-Miller generator
function srandom( seedobj, fVal1, fVal2 )
    local seed = seedobj[1]
    local k = mod( floor( seed / 127773 ), B )
    seed = mod( 16807 * ( seed - mod( k * 127773, B ) ), B )
    seed = seed - mod( 2836 * k, B )
    if seed < 0 then seed = mod( seed + B - 1, B ) end
    seedobj[1] = seed
    local temp_rand = seed / ( B - 1 )
    if fVal2 then
        return floor( fVal1 + 0.5 + temp_rand * ( fVal2 - fVal1 ) )
    elseif fVal1 then
        return floor( temp_rand * fVal1 ) + 1
    else
        return temp_rand
    end
end

-- test
local seedobj = { 2 }   -- first element is the seed and must not be 0
for i = 1, 100 do
    print( srandom( seedobj, 100, 1000 ) )
end

我没有安装Lua4.0,也从未使用过它,因此下面的代码可能需要一些调整

这是在Lua5.1上工作的东西。这是对用C编写的Park和Miller生成器实现的粗略修改,使用32位整数。我试图更接近我从您的代码片段中猜到的4.0语法。测试它,看看它的周期是否适合你的需要。原始版本的周期约为2e9,但转换为浮点运算可能会破坏某些东西这些生成器是非常微妙的事情

local mod = math.fmod
local floor = math.floor

local B = 2^31
-- rough adaptation of Park-Miller generator
function srandom( seedobj, fVal1, fVal2 )
    local seed = seedobj[1]
    local k = mod( floor( seed / 127773 ), B )
    seed = mod( 16807 * ( seed - mod( k * 127773, B ) ), B )
    seed = seed - mod( 2836 * k, B )
    if seed < 0 then seed = mod( seed + B - 1, B ) end
    seedobj[1] = seed
    local temp_rand = seed / ( B - 1 )
    if fVal2 then
        return floor( fVal1 + 0.5 + temp_rand * ( fVal2 - fVal1 ) )
    elseif fVal1 then
        return floor( temp_rand * fVal1 ) + 1
    else
        return temp_rand
    end
end

-- test
local seedobj = { 2 }   -- first element is the seed and must not be 0
for i = 1, 100 do
    print( srandom( seedobj, 100, 1000 ) )
end

这里是另一个尝试总是Lua5.1代码,使用Knuth非线性同余从减法生成器的C改编而来。根据Knuth的说法,即使是单精度,它也应该与FP算法一起工作

local mod = math.fmod
local floor = math.floor
local abs = math.abs

local B =  4000000

-- rough adaptation of Knuth float generator
function srandom( seedobj, fVal1, fVal2 )
    local ma = seedobj.ma
    local seed = seedobj.seed
    local mj, mk
    if seed < 0 or not ma then
        ma = {}
        seedobj.ma = ma
        mj = abs( 1618033 - abs( seed ) )
        mj = mod( mj, B )
        ma[55] = mj
        mk = 1
        for i = 1, 54 do
            local ii = mod( 21 * i,  55 )
            ma[ii] = mk
            mk = mj - mk
            if mk < 0 then mk = mk + B end
            mj = ma[ii]
        end
        for k = 1, 4 do
            for i = 1, 55 do
                ma[i] = ma[i] - ma[ 1 + mod( i + 30,  55) ]
                if ma[i] < 0 then ma[i] = ma[i] + B end
            end
        end
        seedobj.inext = 0
        seedobj.inextp = 31
        seedobj.seed = 1
    end -- if
    local inext = seedobj.inext
    local inextp = seedobj.inextp
    inext = inext + 1
    if inext == 56 then inext = 1 end
    seedobj.inext = inext
    inextp = inextp + 1
    if inextp == 56 then inextp = 1 end
    seedobj.inextp = inextp
    mj = ma[ inext ] - ma[ inextp ]
    if mj < 0 then mj = mj + B end
    ma[ inext ] = mj
    local temp_rand = mj / B
    if fVal2 then
        return floor( fVal1 + 0.5 + temp_rand * ( fVal2 - fVal1 ) )
    elseif fVal1 then
        return floor( temp_rand * fVal1 ) + 1
    else
        return temp_rand
    end
end

-- test

-- Note: seedobj must be a table with a field named `seed`;
-- this field must be negative; after the first number has
-- been generated, the seedobj table will be populated with
-- additional state needed to generate numbers; changing its
-- `seed` field to a negative number will reinitialize the
-- generator and start a new pseudorandom sequence.
local seedobj = { seed = -232343 }
for i = 1, 100 do
    print( srandom( seedobj, 100, 1000 ) )
end

这里是另一个尝试总是Lua5.1代码,使用Knuth非线性同余从减法生成器的C改编而来。根据Knuth的说法,即使是单精度,它也应该与FP算法一起工作

local mod = math.fmod
local floor = math.floor
local abs = math.abs

local B =  4000000

-- rough adaptation of Knuth float generator
function srandom( seedobj, fVal1, fVal2 )
    local ma = seedobj.ma
    local seed = seedobj.seed
    local mj, mk
    if seed < 0 or not ma then
        ma = {}
        seedobj.ma = ma
        mj = abs( 1618033 - abs( seed ) )
        mj = mod( mj, B )
        ma[55] = mj
        mk = 1
        for i = 1, 54 do
            local ii = mod( 21 * i,  55 )
            ma[ii] = mk
            mk = mj - mk
            if mk < 0 then mk = mk + B end
            mj = ma[ii]
        end
        for k = 1, 4 do
            for i = 1, 55 do
                ma[i] = ma[i] - ma[ 1 + mod( i + 30,  55) ]
                if ma[i] < 0 then ma[i] = ma[i] + B end
            end
        end
        seedobj.inext = 0
        seedobj.inextp = 31
        seedobj.seed = 1
    end -- if
    local inext = seedobj.inext
    local inextp = seedobj.inextp
    inext = inext + 1
    if inext == 56 then inext = 1 end
    seedobj.inext = inext
    inextp = inextp + 1
    if inextp == 56 then inextp = 1 end
    seedobj.inextp = inextp
    mj = ma[ inext ] - ma[ inextp ]
    if mj < 0 then mj = mj + B end
    ma[ inext ] = mj
    local temp_rand = mj / B
    if fVal2 then
        return floor( fVal1 + 0.5 + temp_rand * ( fVal2 - fVal1 ) )
    elseif fVal1 then
        return floor( temp_rand * fVal1 ) + 1
    else
        return temp_rand
    end
end

-- test

-- Note: seedobj must be a table with a field named `seed`;
-- this field must be negative; after the first number has
-- been generated, the seedobj table will be populated with
-- additional state needed to generate numbers; changing its
-- `seed` field to a negative number will reinitialize the
-- generator and start a new pseudorandom sequence.
local seedobj = { seed = -232343 }
for i = 1, 100 do
    print( srandom( seedobj, 100, 1000 ) )
end
我找到了一个解决方案:

我不知道统计特性,但即使经过数千次迭代,函数也不会返回重复值。不管怎样,谢谢大家的帮助

我找到了一个解决方案:



我不知道统计特性,但即使经过数千次迭代,函数也不会返回重复值。不管怎样,谢谢大家的帮助

如果你可以访问os.clock,这将为你提供一个合适的种子。所以我不得不问,为什么math.random不可用?这是一个视频游戏,开发人员决定用一个函数替换/覆盖random,该函数在每次游戏开始时都会获得一个新的种子。我需要一个脚本,我可以依靠它在每次运行脚本时使用相同的种子生成相同的结果。从时钟获取种子对我没有帮助。有人用Lua重写了Marsenne twister脚本吗?如果你能找到用Lua编写的,你可以使用任何哈希函数作为好的伪随机数生成器。如果你可以访问os.clock,这应该会为你提供合适的种子。所以我还是要问一下,为什么math.random不可用?它是用于视频游戏的,开发者决定用一个函数替换/覆盖random,该函数在每次游戏开始时都会得到一个新的种子。我需要一个脚本,我可以依靠它在每次运行脚本时使用相同的种子生成相同的结果。从时钟获取种子对我没有帮助。有人用Lua重写了Marsenne twister脚本吗?如果你能找到用Lua编写的哈希函数,你可以使用任何哈希函数作为好的伪随机数生成器。我对你的代码也有同样的问题。这些数字开始重复。在这种情况下,他们开始重复大约8500次迭代,这是一个改进,但仍然很糟糕。在这个游戏的讨论板上,有人向我建议,它附带的Lua版本被编译为使用单精度浮点而不是双精度浮点。如果是这种情况,我不知道该怎么办。@posfan12如果Lua数是单精度FP,那么这很可能是srandom周期太短的原因,因为单精度浮点只有23个IIRC位的有效位,这太少了,无法在没有舍入的情况下执行32位整数计算。有些算法是专门设计用来处理16位整数的,但我手头没有。调整其中一个可能会起作用。@posfan12要测试您的数字是否为单精度,请执行此行print2^25。双精度可以处理它没有问题,打印33554432。如果得到不同的结果,则可能是单精度数字。我得到了相同的结果。print2^1000是否打印类似于1.0715086071863e+301的内容?我对您的代码有相同的问题。这些数字开始重复。在这种情况下,他们开始重复大约8500次迭代,这是一个改进,但仍然很糟糕。在游戏的讨论板上,有人向我建议Lua的版本包括

它被编译为使用单精度浮点而不是双精度浮点。如果是这种情况,我不知道该怎么办。@posfan12如果Lua数是单精度FP,那么这很可能是srandom周期太短的原因,因为单精度浮点只有23个IIRC位的有效位,这太少了,无法在没有舍入的情况下执行32位整数计算。有些算法是专门设计用来处理16位整数的,但我手头没有。调整其中一个可能会起作用。@posfan12要测试您的数字是否为单精度,请执行此行print2^25。双精度可以处理它没有问题,打印33554432。如果你得到不同的结果,你可能有单精度的数字。我得到了相同的结果。print2^1000打印类似于1.0715086071863e+301的东西吗?这个似乎效果更好。这里和那里有一些重复的值,但它们是零星的。在10000次迭代之后,只有12次重复,而之前的尝试只有几百次或几千次。不过,我必须将所有其他脚本重写为seedobj的新格式。在我接受这个答案之前,我会再做一些测试。@posfan12对不起,也许我不明白。您是否正在寻找一个在结束周期之前不重复任何数字的生成器?如果是这样的话,你的要求可能有点太高了。像这样的伪随机生成器不会试图不重复数字,因为序列必须类似于实际的随机序列,即滚动模具的结果。如果在整个序列重复之前附加了一个额外的限制,即任何已经看到的数字都不能再次看到,那么这就是扭曲了序列的随机性,使其更加可预测。@posfan12当然,在某些应用程序中,您确实希望避免任何重复,并且有一些技术可以实现这一点,但是你确定你需要吗。避免重复并不会增加序列的随机性,如果这是你想要的,则恰恰相反。少量重复是可以的,只要它们不是一行。我正在使用脚本绘制视频游戏对象的3D点,因此,如果所有三个坐标重复并导致对象重叠,可能会在游戏中造成问题。LCG功能会产生可见的伪影,所以我还是使用了这个。谢谢这个似乎更好用。这里和那里有一些重复的值,但它们是零星的。在10000次迭代之后,只有12次重复,而之前的尝试只有几百次或几千次。不过,我必须将所有其他脚本重写为seedobj的新格式。在我接受这个答案之前,我会再做一些测试。@posfan12对不起,也许我不明白。您是否正在寻找一个在结束周期之前不重复任何数字的生成器?如果是这样的话,你的要求可能有点太高了。像这样的伪随机生成器不会试图不重复数字,因为序列必须类似于实际的随机序列,即滚动模具的结果。如果在整个序列重复之前附加了一个额外的限制,即任何已经看到的数字都不能再次看到,那么这就是扭曲了序列的随机性,使其更加可预测。@posfan12当然,在某些应用程序中,您确实希望避免任何重复,并且有一些技术可以实现这一点,但是你确定你需要吗。避免重复并不会增加序列的随机性,如果这是你想要的,则恰恰相反。少量重复是可以的,只要它们不是一行。我正在使用脚本绘制视频游戏对象的3D点,因此,如果所有三个坐标重复并导致对象重叠,可能会在游戏中造成问题。LCG功能会产生可见的伪影,所以我还是使用了这个。谢谢该死。LCG函数生成的平面和本线程其他地方描述的平面非常明显。我不能用这个功能。该死。LCG函数生成的平面和本线程其他地方描述的平面非常明显。我不能使用这个功能。