radiate_core/stats/
statistics.rs1use core::f32;
2
3#[derive(PartialEq, Clone)]
4pub struct Adder {
5 compensation: f32,
6 simple_sum: f32,
7 sum: f32,
8}
9
10impl Adder {
11 pub fn value(&self) -> f32 {
12 let result = self.sum + self.compensation;
13 if result.is_nan() {
14 self.simple_sum
15 } else {
16 result
17 }
18 }
19
20 pub fn add(&mut self, value: f32) {
21 let y = value - self.compensation;
22 let t = self.sum + y;
23
24 self.compensation = (t - self.sum) - y;
25 self.sum = t;
26 self.simple_sum += value;
27 }
28}
29
30impl Default for Adder {
31 fn default() -> Self {
32 Adder {
33 compensation: 0_f32,
34 simple_sum: 0_f32,
35 sum: 0_f32,
36 }
37 }
38}
39
40#[derive(PartialEq, Clone)]
41pub struct Statistic {
42 m1: Adder,
43 m2: Adder,
44 m3: Adder,
45 m4: Adder,
46 sum: Adder,
47 count: i32,
48 last_value: f32,
49 max: f32,
50 min: f32,
51}
52
53impl Statistic {
54 pub fn new(initial_val: f32) -> Self {
55 let mut result = Statistic::default();
56 result.add(initial_val);
57 result
58 }
59
60 pub fn last_value(&self) -> f32 {
61 self.last_value
62 }
63
64 pub fn count(&self) -> i32 {
65 self.count
66 }
67
68 pub fn min(&self) -> f32 {
69 self.min
70 }
71
72 pub fn max(&self) -> f32 {
73 self.max
74 }
75
76 pub fn mean(&self) -> f32 {
77 if self.count == 0 {
78 0_f32
79 } else {
80 self.m1.value()
81 }
82 }
83
84 pub fn sum(&self) -> f32 {
85 self.sum.value()
86 }
87
88 pub fn variance(&self) -> f32 {
89 let mut value = f32::NAN;
90 if self.count == 1 {
91 value = self.m2.value();
92 } else if self.count > 1 {
93 value = self.m2.value() / (self.count - 1) as f32;
94 }
95
96 value
97 }
98
99 pub fn std_dev(&self) -> f32 {
100 self.variance().sqrt()
101 }
102
103 pub fn skewness(&self) -> f32 {
104 let mut value = f32::NAN;
105 if self.count >= 3 {
106 let temp = self.m2.value() / self.count as f32 - 1_f32;
107 if temp < 10e-10_f32 {
108 value = 0_f32;
109 } else {
110 value = self.count as f32 * self.m3.value()
111 / ((self.count as f32 - 1_f32)
112 * (self.count as f32 - 2_f32)
113 * temp.sqrt()
114 * temp)
115 }
116 }
117
118 value
119 }
120
121 pub fn kurtosis(&self) -> f32 {
122 let mut value = f32::NAN;
123 if self.count >= 4 {
124 let temp = self.m2.value() / self.count as f32 - 1_f32;
125 if temp < 10e-10_f32 {
126 value = 0_f32;
127 } else {
128 value = self.count as f32 * (self.count as f32 + 1_f32) * self.m4.value()
129 / ((self.count as f32 - 1_f32)
130 * (self.count as f32 - 2_f32)
131 * (self.count as f32 - 3_f32)
132 * temp
133 * temp)
134 }
135 }
136
137 value
138 }
139
140 pub fn add(&mut self, value: f32) {
141 self.count += 1;
142
143 let n = self.count as f32;
144 let d = value - self.m1.value();
145 let dn = d / n;
146 let dn2 = dn * dn;
147 let t1 = d * dn * (n - 1_f32);
148
149 self.m1.add(dn);
150
151 self.m4.add(t1 * dn2 * (n * n - 3_f32 * n + 3_f32));
152 self.m4
153 .add(6_f32 * dn2 * self.m2.value() - 4_f32 * dn * self.m3.value());
154
155 self.m3
156 .add(t1 * dn * (n - 2_f32) - 3_f32 * dn * self.m2.value());
157 self.m2.add(t1);
158
159 self.last_value = value;
160 self.max = if value > self.max { value } else { self.max };
161 self.min = if value < self.min { value } else { self.min };
162 self.sum.add(value);
163 }
164
165 pub fn clear(&mut self) {
166 self.m1 = Adder::default();
167 self.m2 = Adder::default();
168 self.m3 = Adder::default();
169 self.m4 = Adder::default();
170 self.sum = Adder::default();
171 self.count = 0;
172 self.last_value = 0_f32;
173 self.max = f32::MIN;
174 self.min = f32::MAX;
175 }
176}
177
178impl Default for Statistic {
179 fn default() -> Self {
180 Statistic {
181 m1: Adder::default(),
182 m2: Adder::default(),
183 m3: Adder::default(),
184 m4: Adder::default(),
185 sum: Adder::default(),
186 count: 0,
187 last_value: 0_f32,
188 max: f32::MIN,
189 min: f32::MAX,
190 }
191 }
192}
193
194impl From<f32> for Statistic {
195 fn from(value: f32) -> Self {
196 Statistic::new(value)
197 }
198}
199
200impl From<i32> for Statistic {
201 fn from(value: i32) -> Self {
202 Statistic::new(value as f32)
203 }
204}
205
206impl From<usize> for Statistic {
207 fn from(value: usize) -> Self {
208 Statistic::new(value as f32)
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_adder() {
218 let mut adder = Adder::default();
219 adder.add(1_f32);
220 adder.add(2_f32);
221 adder.add(3_f32);
222 adder.add(4_f32);
223 adder.add(5_f32);
224
225 assert_eq!(adder.value(), 15_f32);
226 }
227
228 #[test]
229 fn test_statistic() {
230 let mut statistic = Statistic::default();
231 statistic.add(1_f32);
232 statistic.add(2_f32);
233 statistic.add(3_f32);
234 statistic.add(4_f32);
235 statistic.add(5_f32);
236
237 assert_eq!(statistic.mean(), 3_f32);
238 assert_eq!(statistic.variance(), 2.5_f32);
239 assert_eq!(statistic.std_dev(), 1.5811388_f32);
240 assert_eq!(statistic.skewness(), 0_f32);
241 }
242}