hydro_std/bench_client/
rolling_average.rs

1use serde::{Deserialize, Serialize};
2
3/// Rolling statistics tracker for computing mean, standard deviation, and confidence intervals
4#[derive(Clone, Debug, Serialize, Deserialize)]
5pub struct RollingAverage {
6    samples: Vec<f64>,
7    sum: f64,
8    sum_squares: f64,
9    count: usize,
10}
11
12impl Default for RollingAverage {
13    fn default() -> Self {
14        Self::new()
15    }
16}
17
18impl RollingAverage {
19    pub fn new() -> Self {
20        Self {
21            samples: Vec::new(),
22            sum: 0.0,
23            sum_squares: 0.0,
24            count: 0,
25        }
26    }
27
28    pub fn add_sample(&mut self, value: f64) {
29        self.samples.push(value);
30        self.sum += value;
31        self.sum_squares += value * value;
32        self.count += 1;
33    }
34
35    pub fn sample_count(&self) -> usize {
36        self.count
37    }
38
39    pub fn sample_mean(&self) -> f64 {
40        if self.count == 0 {
41            0.0
42        } else {
43            self.sum / self.count as f64
44        }
45    }
46
47    pub fn sample_variance(&self) -> f64 {
48        if self.count <= 1 {
49            0.0
50        } else {
51            let mean = self.sample_mean();
52            (self.sum_squares - self.count as f64 * mean * mean) / (self.count - 1) as f64
53        }
54    }
55
56    pub fn sample_std_dev(&self) -> f64 {
57        self.sample_variance().sqrt()
58    }
59
60    /// Compute 99% confidence interval for the mean using t-distribution approximation
61    pub fn confidence_interval_99(&self) -> Option<(f64, f64)> {
62        if self.count < 2 {
63            return None;
64        }
65
66        let mean = self.sample_mean();
67        let std_dev = self.sample_std_dev();
68        let std_error = std_dev / (self.count as f64).sqrt();
69
70        // t-value for 99% confidence interval (approximation for large n)
71        let t_value = 2.576; // z-score for 99% confidence
72
73        let margin = t_value * std_error;
74        Some((mean - margin, mean + margin))
75    }
76
77    /// Combine two RollingAverage instances
78    pub fn add(&mut self, other: Self) {
79        for sample in other.samples {
80            self.add_sample(sample);
81        }
82    }
83}