hopr_utils/statistics/moving/
exponential.rs1#[derive(Debug, Copy, Clone, Default, PartialEq)]
10pub struct ExponentialMovingAverage<const FACTOR: usize> {
11 count: usize,
12 average: f64,
13}
14
15impl<const FACTOR: usize> ExponentialMovingAverage<FACTOR> {
16 const _ASSERT_FACTOR_GT_ZERO: () = assert!(FACTOR > 0, "FACTOR must be greater than 0");
17
18 pub fn update(&mut self, value: impl Into<f64>) {
20 let value: f64 = value.into();
21 self.count += 1;
22 self.average = self.average + (value - self.average) / (std::cmp::min(self.count, FACTOR) as f64);
23 }
24
25 pub fn get(&self) -> f64 {
27 self.average
28 }
29}
30
31#[cfg(test)]
32mod tests {
33 use assertables::{assert_f64_eq, assert_in_delta};
34
35 #[test]
36 fn running_average_should_compute_the_windowed_average_correctly() {
37 let mut avg = super::ExponentialMovingAverage::<5>::default();
38
39 for i in 1..=10 {
40 avg.update(i);
41 }
42
43 assert_in_delta!(avg.get(), 6.6, 0.1);
44 }
45
46 #[test]
47 fn running_average_should_compute_the_average_from_constant_correctly() {
48 let mut avg = super::ExponentialMovingAverage::<5>::default();
49
50 for _ in 1..=10 {
51 avg.update(3);
52 }
53
54 assert_f64_eq!(avg.get(), 3.0);
55 }
56}