2012-08-02 10:52:28 +00:00
|
|
|
-- Pseudo random number generation module for Lunatic
|
|
|
|
|
|
|
|
local ffi = require("ffi")
|
|
|
|
local ffiC = ffi.C
|
|
|
|
|
|
|
|
local rawset = rawset
|
|
|
|
|
|
|
|
local type = type
|
2012-11-25 13:18:52 +00:00
|
|
|
local decl = decl -- comes from above (defs.ilua)
|
2012-08-02 10:52:28 +00:00
|
|
|
|
|
|
|
local print = print -- for commented out debug block in new() below
|
|
|
|
|
|
|
|
module(...)
|
|
|
|
|
|
|
|
|
2012-11-25 13:18:52 +00:00
|
|
|
-- PRNG state struct
|
2012-08-02 10:52:28 +00:00
|
|
|
ffi.cdef[[
|
2012-11-25 13:18:52 +00:00
|
|
|
typedef struct {
|
|
|
|
uint32_t x, y, z, c;
|
|
|
|
} rng_jkiss_t;
|
|
|
|
|
2012-08-02 10:52:28 +00:00
|
|
|
typedef union { unsigned char u[16]; double d[2]; } uchar_double_u_t;
|
|
|
|
typedef union { unsigned char u[16]; uint32_t i[4]; } uchar_uint_u_t;
|
|
|
|
]]
|
|
|
|
|
2012-11-25 13:18:52 +00:00
|
|
|
-- PRNG functions
|
|
|
|
decl[[
|
|
|
|
uint32_t rand_jkiss_u32(rng_jkiss_t *s);
|
|
|
|
double rand_jkiss_dbl(rng_jkiss_t *s);
|
|
|
|
|
|
|
|
void md4once(const unsigned char *block, unsigned int len, unsigned char digest [16]);
|
|
|
|
]]
|
|
|
|
|
2012-08-02 10:52:28 +00:00
|
|
|
local mt = {
|
|
|
|
__tostring = function(s)
|
|
|
|
return "rand.new("..s.x..","..s.y..","..s.z..","..s.c..")"
|
|
|
|
end,
|
|
|
|
|
|
|
|
__index = {
|
|
|
|
getu32 = ffiC.rand_jkiss_u32,
|
|
|
|
getdbl = ffiC.rand_jkiss_dbl,
|
|
|
|
|
|
|
|
-- Initialize the JKISS PRNG using the MD4 of the lower bits of the
|
|
|
|
-- profiling timer
|
|
|
|
init_time_md4 = function(s)
|
|
|
|
local tin = ffi.new("uchar_double_u_t")
|
|
|
|
local tout = ffi.new("uchar_uint_u_t")
|
|
|
|
|
|
|
|
repeat
|
2012-11-25 13:18:52 +00:00
|
|
|
tin.d[0] = ffiC.gethitickms() % 1
|
|
|
|
tin.d[1] = ffiC.gethitickms() % 1
|
2012-08-02 10:52:28 +00:00
|
|
|
|
|
|
|
ffiC.md4once(tin.u, 16, tout.u)
|
|
|
|
|
|
|
|
s.y = tout.u[1]
|
|
|
|
until (s.y ~= 0) -- y must not be zero!
|
|
|
|
|
|
|
|
s.x = tout.u[0]
|
|
|
|
s.z = tout.u[2]
|
|
|
|
s.c = tout.u[3] % 698769068 + 1 -- Should be less than 698769069
|
|
|
|
end,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
local jkiss = ffi.metatype("rng_jkiss_t", mt)
|
|
|
|
|
|
|
|
function new(x,y,z,c)
|
|
|
|
local s
|
|
|
|
if (x == nil or type(x)=="boolean") then
|
2012-08-19 12:52:18 +00:00
|
|
|
-- initialize with arbitrary but fixed state
|
|
|
|
s = jkiss(123456789, 987654321, 43219876, 6543217)
|
2012-08-02 10:52:28 +00:00
|
|
|
if (x) then
|
|
|
|
s:init_time_md4()
|
|
|
|
end
|
|
|
|
else
|
|
|
|
s = jkiss(x,y,z,c)
|
|
|
|
end
|
|
|
|
--[[
|
|
|
|
print("TEST")
|
|
|
|
local r=ffi.new("rng_jkiss_t")
|
|
|
|
r.x = 123456789; r.y = 987654321; r.z = 43219876; r.c = 6543217;
|
|
|
|
|
|
|
|
t=gv.gethitickms()
|
|
|
|
for i=1,4*2*1e6 do
|
|
|
|
ffiC.rand_jkiss_dbl(r)
|
|
|
|
end
|
|
|
|
print("TIME: "..gv.gethitickms()-t) -- x86_64: approx. 100 ms
|
|
|
|
--]]
|
|
|
|
|
|
|
|
return s
|
|
|
|
end
|