mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-21 01:40:51 +00:00
51c5afaae6
git-svn-id: https://svn.eduke32.com/eduke32@3380 1a8010ca-5511-0410-912e-c29ae57300e0
103 lines
2.5 KiB
Lua
103 lines
2.5 KiB
Lua
-- Statistics module for Lunatic.
|
|
|
|
local ffi = require("ffi")
|
|
|
|
local math = require("math")
|
|
local string = require("string")
|
|
|
|
local tostring = tostring
|
|
|
|
|
|
module(...)
|
|
|
|
|
|
ffi.cdef[[
|
|
typedef struct {
|
|
double n;
|
|
// vvv internal vvv
|
|
double m, s;
|
|
double min, max;
|
|
} runningstat_t;
|
|
|
|
typedef struct {
|
|
const double n;
|
|
const double mean, var, std;
|
|
const double min, max;
|
|
} runningstat_res_t;
|
|
]]
|
|
|
|
|
|
local NaN = 0/0
|
|
|
|
local res_mt = {
|
|
__tostring = function(s)
|
|
return
|
|
string.format("N=%d; mean=%.5g, std=%.5g; min=%.5g, max=%.5g",
|
|
s.n, s.mean, s.std, s.min, s.max)
|
|
end
|
|
}
|
|
local rstatres = ffi.metatype("runningstat_res_t", res_mt)
|
|
|
|
|
|
local mt = {
|
|
__tostring = function(s)
|
|
-- XXX: with this and the other serializing of ffi types, take care of
|
|
-- NaN and Infs when reading back (e.g. by "nan=0/0" in that context)
|
|
return "stat.new("..s.n..","..s.m..","..s.s..","..s.min..","..s.max..")"
|
|
end,
|
|
|
|
-- See: Accurately computing running variance, by John D. Cook
|
|
-- http://www.johndcook.com/standard_deviation.html
|
|
__index = {
|
|
add = function(s, num)
|
|
if (s.n > 0) then
|
|
-- N>0, recurrence
|
|
s.n = s.n+1
|
|
|
|
local lastm = s.m
|
|
s.m = lastm + (num-lastm)/s.n
|
|
s.s = s.s + (num-lastm)*(num-s.m)
|
|
|
|
if (num < s.min) then s.min = num end
|
|
if (num > s.max) then s.max = num end
|
|
else
|
|
-- N==0, initialization
|
|
s.n = 1
|
|
|
|
s.m = num
|
|
s.s = 0
|
|
|
|
s.min = num
|
|
s.max = num
|
|
end
|
|
end,
|
|
|
|
getstats = function(s)
|
|
local var = s.n > 1 and s.s/(s.n-1) or NaN
|
|
return rstatres(s.n, s.m, var, math.sqrt(var), s.min, s.max)
|
|
end,
|
|
|
|
getstatstr = function(s)
|
|
return tostring(s:getstats())
|
|
end,
|
|
|
|
reset = function(s)
|
|
s.n = 0
|
|
s.m, s.s, s.min, s.max = NaN, NaN, NaN, NaN
|
|
end,
|
|
},
|
|
}
|
|
local rstat = ffi.metatype("runningstat_t", mt)
|
|
|
|
function new(n,m,s, min,max)
|
|
if (n == nil) then
|
|
-- initialization containing no elements
|
|
return rstat(0, NaN, NaN, NaN, NaN)
|
|
elseif (m == nil) then
|
|
-- same as initialization with N==0 above (one element)
|
|
return rstat(1, n, 0, n, n)
|
|
else
|
|
-- generic initialization (internal use only)
|
|
return rstat(n,m,s, min,max)
|
|
end
|
|
end
|