Last active
January 5, 2019 06:54
-
-
Save hmenke/481c4b669bdbb2ec8bfc24c6097d415b to your computer and use it in GitHub Desktop.
Legacy RNG from Lua 5.2 for Lua 5.3
This file contains 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
/* | |
This program reimplements the GNU glibc random number generator. | |
https://www.mathstat.dal.ca/~selinger/random/ | |
https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=stdlib/random_r.c | |
*/ | |
#include <assert.h> | |
#include <stdlib.h> | |
static int r[344]; | |
#define GNU_RAND_MAX 2147483647 | |
// https://stackoverflow.com/a/27030128 | |
int add(int a, int b) { | |
if(b == 0) | |
return a; | |
return add(a ^ b, (a & b) << 1); | |
} | |
void gnu_srand(unsigned int seed) { | |
if (seed == 0) { | |
seed = 1; | |
} | |
r[0] = seed; | |
for (int i = 1; i < 31; ++i) { | |
/* (from stdlib/random_r.c) This does: | |
r[i] = (16807 * r[i - 1]) % 2147483647; | |
but avoids overflowing 31 bits. */ | |
int hi = r[i - 1] / 127773; | |
int lo = r[i - 1] % 127773; | |
r[i] = (16807 * lo - 2836 * hi) & 0xffffffff; | |
} | |
for (int i = 31; i < 34; ++i) { | |
r[i] = r[i - 31]; | |
} | |
for (int i = 34; i < 344; ++i) { | |
r[i] = add(r[i - 31], r[i - 3]); | |
} | |
} | |
int gnu_rand() { | |
static int i = 0; | |
r[i] = add(r[(i - 31 + 344) % 344], r[(i - 3 + 344) % 344]); | |
int x = (r[i] & 0xffffffff) >> 1; | |
i = (i + 1) % 344; | |
return x; | |
} | |
int main() { | |
/* The default seed is 1 */ | |
gnu_srand(1); | |
assert(GNU_RAND_MAX == RAND_MAX); | |
srand(42); | |
gnu_srand(42); | |
for (int i = 0; i < 1000000; ++i) { | |
assert(gnu_rand() == rand()); | |
} | |
} |
This file contains 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
--[[ | |
This snippet implements the legacy Lua 5.2 random number generator for | |
Lua 5.3. Even though Lua 5.3 can do bitwise operations, we use the | |
bit32 library such that the code can be parsed by both Lua 5.2 and Lua | |
5.3. If you don't care about that, you can simply replace the bit32 | |
calls with bitwise operations. | |
--]] | |
local ok, bit32 = pcall(require, "bit32") | |
if not ok then | |
ok, bit32 = pcall(require, "bit") | |
end | |
if not ok then | |
error("No bitwise operations available") | |
end | |
--if _VERSION == "Lua 5.3" or type(jit) == "table" then | |
do | |
local add -- https://stackoverflow.com/a/27030128 | |
add = function(a,b) | |
if (bit32.bxor(b,0x0) == 0) then | |
return a | |
end | |
return add(bit32.bxor(a,b), bit32.lshift(bit32.band(a,b),1)) | |
end | |
local r = {} | |
local ffffffff = bit32.bnot(0x00000000) | |
local RAND_MAX = 2147483647 | |
local i = 0 | |
local rand = function() | |
i = i % 344 + 1 | |
r[i] = add(r[(i - 32 + 344) % 344 + 1], r[(i - 4 + 344) % 344 + 1]) | |
local r = bit32.rshift(bit32.band(r[i], ffffffff), 1) | |
return r | |
end | |
local srand = function(seed) | |
-- can't seed with 0 | |
if seed == 0 then | |
seed = 1 | |
end | |
r[1] = seed | |
for i = 2, 31 do | |
--[[ (from stdlib/random_r.c) This does: | |
r[i] = (16807 * r[i - 1]) % 2147483647; | |
but avoids overflowing 31 bits. ]] | |
local hi = math.floor(r[i - 1] / 127773) | |
local lo = r[i - 1] % 127773 | |
r[i] = bit32.band(16807 * lo - 2836 * hi, ffffffff) | |
end | |
for i = 32, 34 do | |
r[i] = r[i-31] | |
end | |
for i = 35, 344 do | |
r[i] = add(r[i-31], r[i-3]) | |
end | |
end | |
function math.random(l,u) | |
local r = rand() / RAND_MAX | |
if l and u then -- lower and upper limits | |
assert(l <= u, "interval is empty") | |
return math.floor(r*(u-l+1)) + l | |
elseif l then -- only upper limit | |
assert(1.0 <= u, "interval is empty") | |
return math.floor(r*u) + 1.0 | |
else -- no arguments | |
return r | |
end | |
end | |
function math.randomseed(seed) | |
if seed < 0 then | |
srand(math.floor(seed)) | |
else | |
srand(math.ceil(seed)) | |
end | |
rand() -- discard first value to avoid undesirable correlations | |
end | |
-- the default seed is 1 | |
srand(1) | |
end | |
math.randomseed(42) | |
for i = 0, 10000000 do | |
print(math.random()) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment