-
Notifications
You must be signed in to change notification settings - Fork 0
/
stats.h
178 lines (156 loc) · 3.87 KB
/
stats.h
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#ifndef STATS_H
#define STATS_H
#include <stddef.h>
#include <tgmath.h>
#include <stdio.h>
/**
** @file
** @brief Collect some simple statistics online as we go.
**
** This uses a generalization of Welford's trick to compute running
** mean and variance. See
**
** Philippe Pébay. Formulas for robust, one-pass parallel computation
** of covariances and arbitrary-order statistical moments. Technical
** Report SAND2008-6212, SANDIA, 2008. URL
** http://prod.sandia.gov/techlib/access-control.cgi/2008/086212.pdf.
**/
typedef struct stats stats;
/**
** @brief A simple data structure to collect the 0th to 3rd moment of
** a statistic.
**
** @warning Since this also uses a @c double for the number of
** samples, the validity of all this is restricted to about
** @f$2^{50}@f$ samples.
**/
struct stats {
double moment[4];
};
stats stats_new(void) {
stats ret;
ret.moment[0] = 0.0;
ret.moment[1] = 0.0;
ret.moment[2] = 0.0;
ret.moment[3] = 0.0;
return ret;
}
/**
** @brief Return the number of samples that had been entered into the
** statistic @a c.
**/
inline
double stats_samples(stats* c) {
return c->moment[0];
}
/**
** @brief Return the mean value of the samples that had been entered
** into the statistic @a c.
**/
inline
double stats_mean(stats* c) {
return c->moment[1];
}
/**
** @brief Return the variance of the samples that had been entered
** into the statistic @a c.
**/
inline
double stats_var(stats* c) {
return c->moment[2]/stats_samples(c);
}
/**
** @brief Return the standard deviation of the samples that had been
** entered into the statistic @a c.
**/
static inline
double stats_sdev(stats* c) {
return sqrt(stats_var(c));
}
/**
** @brief Return the relative standard deviation of the samples that
** had been entered into the statistic @a c.
**/
static inline
double stats_rsdev(stats* c) {
return sqrt(stats_var(c))/stats_mean(c);
}
/**
** @brief Return the normalized skew of the samples that had been
** entered into the statistic @a c.
**/
static inline
double stats_skew(stats* c) {
double var = stats_var(c);
return (c->moment[3]/pow(var, 1.5))/stats_samples(c);
}
/**
** @brief Return the unbiased variance of the samples that had been
** entered into the statistic @a c.
**
** Use Bessel's correction to have an estimation of the unbiased
** variance of the overall population.
**/
static inline
double stats_var_unbiased(stats* c) {
return c->moment[2]/(stats_samples(c)-1);
}
/**
** @brief Return the unbiased standard deviation of the samples that
** had been entered into the statistic @a c.
**
** Use Bessel's correction to have an less biased estimation of the
** variance of the overall population.
**/
static inline
double stats_sdev_unbiased(stats* c) {
return sqrt(stats_var_unbiased(c));
}
/**
** @brief Return the unbiased relative standard deviation of the
** samples that had been entered into the statistic @a c.
**/
static inline
double stats_rsdev_unbiased(stats* c) {
return stats_rsdev(c)*(1+1/(4*stats_samples(c)));
}
/**
** @brief Add value @a val to the statistic @a c.
**/
inline
void stats_collect(stats* c, double val, unsigned moments) {
double n = stats_samples(c);
double n0 = n-1;
double n1 = n+1;
double delta0 = 1;
double delta = val - stats_mean(c);
double delta1 = delta/n1;
double delta2 = delta1*delta*n;
switch (moments) {
default:
c->moment[3] += (delta2*n0 - 3*c->moment[2])*delta1;
case 2:
c->moment[2] += delta2;
case 1:
c->moment[1] += delta1;
case 0:
c->moment[0] += delta0;
}
}
inline
void stats_collect0(stats* c, double val) {
stats_collect(c, val, 0);
}
inline
void stats_collect1(stats* c, double val) {
stats_collect(c, val, 1);
}
inline
void stats_collect2(stats* c, double val) {
stats_collect(c, val, 2);
}
inline
void stats_collect3(stats* c, double val) {
stats_collect(c, val, 3);
}
#endif //STATS_H