/
prng.lua
56 lines (47 loc) · 1.42 KB
/
prng.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
--------------------------------------------------------------------------------
-- Pseudo random number generators module.
--
-- Copyright (C) 2011-2016 Stefano Peluchetti. All rights reserved.
--------------------------------------------------------------------------------
local ffi = require "ffi"
local marsaglia = require "sci.prng._marsaglia"
local mrg = require "sci.prng._mrg"
local M = {
std = marsaglia.lfib4,
lfib4 = marsaglia.lfib4,
kiss99 = marsaglia.kiss99,
mrg32k3a = mrg.mrg32k3a,
}
local function restore_unsafe(str)
assert(type(str) == "string")
local sep = str:find(" ")
local rng = str:sub(1, sep-1)
local arg = str:sub(sep+1)
return ffi.new(assert(M[rng]), unpack(assert(loadstring("return "..arg))()))
end
local function restore(str)
local ok, rng = pcall(restore_unsafe, str)
if not ok then
error("string is not a valid serialization of a prng")
end
return rng
end
M.restore = restore
local function new_parallel(rng, totalperiod)
return function(n)
local log2n = math.ceil(math.log(n)/math.log(2)) -- Log2.
local rngperiod = totalperiod - log2n
local r = rng()
local out = { }
for i=1,n do
out[i] = r:copy()
r:_sampleahead2pow(rngperiod)
end
return out
end
end
M.parallel = {
mrg32k3a = new_parallel(M.mrg32k3a, 191),
}
M.parallel.std = M.parallel.mrg32k3a
return M