我无法访问Lua 4.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
[编辑]
稍后编辑已删除。
答案 0 :(得分:3)
这是另一种尝试(总是Lua 5.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
答案 1 :(得分:2)
我没有安装Lua 4.0并且从未使用它,因此以下代码可能需要一些调整。
这适用于Lua 5.1。它是Park和Miller生成器的一个实现的粗略改编(用C语言编写,使用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
答案 2 :(得分:2)
我找到了解决方案here:
function mul16(a, b)
local a_lo, b_lo = mod(a, 2^8), mod(b, 2^8)
local a_hi, b_hi = a - a_lo, b - b_lo
return mod(a_lo * b_lo + mod(a_lo * b_hi, 2^16) + mod(a_hi * b_lo, 2^16) + mod(a_hi * b_hi, 2^16), 2^16)
end
function lcg(s, r)
local temp = {}
function temp:random(a, b)
local y = mod(mul16(self.a, self.x) + self.c, self.m)
self.x = y
if not a then
return y / 65536
elseif not b then
if a == 0 then
return y
else
return 1 + mod(y, a)
end
else
return a + mod(y, b - a + 1)
end
end
function temp:randomseed(s)
if not s then
s = seed()
end
self.x = mod(s, 2147483648)
end
-- 'Numerical Recipes' parameters
temp.a = 26125
temp.c = 62303
temp.m = 65536
temp:randomseed(s)
return temp
end
local R = lcg(0974)
local rand_table = {}
for i = 1, 10000 do
local new_value = R:random()
rand_table[i] = new_value
if (i > 1) then
for j = 1, i - 1 do
local old_value = rand_table[j]
if (new_value == old_value) then
print("\ti = " .. i .. "\n\tj = " .. j .. "\n\tnew_value = " .. new_value .. "\n\told_value = " .. old_value)
break
end
end
end
end
我不知道统计属性,但即使经过数千次迭代,函数也不会返回重复值。感谢大家的帮助,无论如何!