Skip to content

Instantly share code, notes, and snippets.

@sakiraykurt
Last active February 24, 2023 12:49
Show Gist options
  • Save sakiraykurt/2b06c42236e145eb3c00f03a2555b68a to your computer and use it in GitHub Desktop.
Save sakiraykurt/2b06c42236e145eb3c00f03a2555b68a to your computer and use it in GitHub Desktop.
Lua random class which is 'Lehmer RNG' formula based.
-- See: https://en.wikipedia.org/wiki/Linear_congruential_generator
-- See: https://en.wikipedia.org/wiki/Lehmer_random_number_generator
-- Original Lehmer RNG construction
local m = 65537 -- (2 ^ 16) + 1, a fermat prime
local a = 75 -- a primitive root modulo
local x0 = 65536 -- a seed number, greater than '0', less than 'm'
local md = m - 1 -- a floating-point devider
-- Lehmer random number generator formula
local function rng(x)
return (x * a) % m
end
-- random min-max number formula
local function rmm(min, max, x)
return min + (x % (max - min))
end
-- random min-max number formula
local function rmmf(min, max, x)
return min + ((max - min) * x)
end
-- checks seed number is valid
local function iv(n)
if type(n) ~= "number" then
error("expected a number!")
end
if n <= 0 or n >= m then
error("invalid seed number!")
end
if n % 1 ~= 0 then
error("seed number should be an integer!")
end
end
-- checks min, max number is valid
local function ivmmd(min, max)
if type(min) ~= "number" or type(max) ~= "number" then
error("expected a number!")
end
if min > max then
error("invalid 'min'-'max' number!")
end
end
-- checks min, max number is valid
local function ivmm(min, max)
ivmmd(min, max)
if min % 1 ~= 0 or max % 1 ~= 0 then
error("seed number should be an integer!")
end
end
local _r = {
-- original seed, current seed
ox = x0,
cx = x0
}
-- get or set a seed value
-- Note: seed number can be between (0, 65537) a integer value
---@param n? integer
---@return integer
function _r:seed(n)
if n ~= nil then
iv(n)
self.ox, self.cx = n, n
end
return self.ox
end
-- get a random integer number between [min, max)
---@param min integer
---@param max integer
---@return integer
function _r:range(min, max)
ivmm(min, max)
self.cx = rng(self.cx)
return rmm(min, max, self.cx)
end
-- get a random floating-point number between [min, max]
---@param min number
---@param max number
---@return number
function _r:rangef(min, max)
ivmmd(min, max)
self.cx = rng(self.cx)
return rmmf(min, max, rmm(0, m, self.cx) / md)
end
-- returns a new instance with/without a seed number
-- Note: seed number can be between (0, 65537) a integer value
---@param seed? integer
function _r:new(seed)
local x = seed or x0
iv(x)
local _inst = setmetatable({ox = x, cx = x}, {__index = self})
return _inst
end
-- returns an instance
return _r
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment