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