1pub mod full {
2 #[derive(Debug)]
3 pub struct Stats {
4 pub min: f64,
5 pub max: f64,
6 pub mean: f64,
7 pub var: f64,
9 pub sample_var: f64,
11 pub stddev: f64,
12 pub sample_stddev: f64,
13 pub p1: f64,
14 pub p5: f64,
15 pub p50: f64,
16 pub p95: f64,
17 pub p99: f64,
18 }
19
20 impl Stats {
21 pub fn compute(values: &[f64]) -> Self {
22 let mut sorted = values.to_vec();
23 sorted.sort_unstable_by(|a, b| a.total_cmp(b));
24 let min = sorted[0];
25 let max = sorted[sorted.len() - 1];
26 let mean = sorted.iter().sum::<f64>() / values.len() as f64;
27 let var = compute_var(values, mean, false);
28 let sample_var = compute_var(values, mean, true);
29 let stddev = var.sqrt();
30 let sample_stddev = sample_var.sqrt();
31 let p1 = percentile_of_sorted(&sorted, 1.0);
32 let p5 = percentile_of_sorted(&sorted, 5.0);
33 let p50 = percentile_of_sorted(&sorted, 50.0);
34 let p95 = percentile_of_sorted(&sorted, 95.0);
35 let p99 = percentile_of_sorted(&sorted, 99.0);
36 Self {
37 min,
38 max,
39 mean,
40 var,
41 sample_var,
42 stddev,
43 sample_stddev,
44 p1,
45 p5,
46 p50,
47 p95,
48 p99,
49 }
50 }
51 }
52
53 fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 {
56 assert!(!sorted_samples.is_empty());
57 if sorted_samples.len() == 1 {
58 return sorted_samples[0];
59 }
60 let zero: f64 = 0.0;
61 assert!(zero <= pct);
62 let hundred = 100_f64;
63 assert!(pct <= hundred);
64 if pct == hundred {
65 return sorted_samples[sorted_samples.len() - 1];
66 }
67 let length = (sorted_samples.len() - 1) as f64;
68 let rank = (pct / hundred) * length;
69 let lrank = rank.floor();
70 let d = rank - lrank;
71 let n = lrank as usize;
72 let lo = sorted_samples[n];
73 let hi = sorted_samples[n + 1];
74 lo + (hi - lo) * d
75 }
76
77 fn compute_var(values: &[f64], mean: f64, sample: bool) -> f64 {
78 if values.len() < 2 {
79 0.0
80 } else {
81 let mut v: f64 = 0.0;
82 for s in values {
83 let x = *s - mean;
84 v += x * x;
85 }
86 let denom = if sample {
90 values.len() - 1
91 } else {
92 values.len()
93 } as f64;
94 v / denom
95 }
96 }
97
98 #[cfg(test)]
99 mod tests {
100 use super::*;
101
102 #[test]
103 fn it_works() {
104 let values = [0.0, 1.0, 3.0, 4.0];
105 dbg!(Stats::compute(&values));
106 }
107 }
108}