Last active
February 24, 2023 12:49
-
-
Save sakiraykurt/2b06c42236e145eb3c00f03a2555b68a to your computer and use it in GitHub Desktop.
Lua random class which is 'Lehmer RNG' formula based.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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