radiate_core/stats/
statistics.rs

1use 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}