local me = { }
-- quick and dirty implementation for test purposes
local fRandomSeedSet = false;
local function setRandomSeed()
if not fRandomSeedSet then
math.randomseed(os.time()+os.clock()*2^16+mw.site.stats.edits*2^16)
fRandomSeedSet = true;
end
end
--[[
Scales up Math.random() by F, so returns a random value in the range [0, F).
]]
function me.randomFloat(F)
setRandomSeed()
return F*math.random()
end -- function me.randomFloat()
--[[
Returns an integer from 0 to M-1.
Uses the following algorithm in order to support values of M > the maximum value supported
by Math.random(upper):
Given a range [0, M): divide it into T partitions, with T-1 partitions of size N, and
the last partition holding the rest. Thus T = ceiling(M/N).
Partition 0 range: [0, N)
Partition 1 range: [N, 2N)
...
Partition T-1 range: [(T-1)*N, M)
Select a partition s = floor(math.random() * M / N)
If s is within range [0, T-2]: result = s*N + floor(me.randomFloat(N))
If s == T-1: result = s*N + floor(me.randomFloat(M-(T-1)*N))
--]]
local defaultPartitionSize = 2^31-1
-- optional parameter: partitionSize
function me.randomInt(M, partitionSize)
setRandomSeed()
local N = defaultPartitionSize
if partitionSize ~= nil then
N = partitionSize
end
-- optimization: if M < partition size N, then no need
-- to partition the output range
if M < N then
return math.floor(me.randomFloat(M))
end
local T = math.ceil(M/N)
local s = math.floor(math.random() * M / N)
local result
if s ~= (T-1) then
result = s * N + math.floor(me.randomFloat(N))
else
result = s * N + math.floor(me.randomFloat(M-(T-1)*N))
end
return result
end -- function me.randomInt()
return me