quantik_core/bench/
metrics.rs1pub fn wilson_ci(hits: u64, n: u64) -> (f64, f64) {
5 let z = 1.96f64;
6 if n == 0 {
7 return (0.0, 0.0);
8 }
9 let n = n as f64;
10 let p = hits as f64 / n;
11 let z2 = z * z;
12 let denom = 1.0 + z2 / n;
13 let centre = (p + z2 / (2.0 * n)) / denom;
14 let margin = z * (p * (1.0 - p) / n + z2 / (4.0 * n * n)).sqrt() / denom;
15 ((centre - margin).max(0.0), (centre + margin).min(1.0))
16}
17
18pub fn mean_std(xs: &[f64]) -> (f64, f64) {
20 let n = xs.len();
21 if n == 0 {
22 return (0.0, 0.0);
23 }
24 let mean = xs.iter().sum::<f64>() / n as f64;
25 if n < 2 {
26 return (mean, 0.0);
27 }
28 let variance = xs.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (n as f64 - 1.0);
29 (mean, variance.sqrt())
30}
31
32pub fn percentile(xs: &[f64], p: f64) -> f64 {
34 if xs.is_empty() {
35 return 0.0;
36 }
37 let mut ordered = xs.to_vec();
38 ordered.sort_by(|a, b| a.total_cmp(b));
39 if ordered.len() == 1 {
40 return ordered[0];
41 }
42 let k = (ordered.len() - 1) as f64 * (p / 100.0);
43 let lo = k.floor() as usize;
44 let hi = k.ceil() as usize;
45 if lo == hi {
46 return ordered[k as usize];
47 }
48 ordered[lo] * (hi as f64 - k) + ordered[hi] * (k - lo as f64)
49}
50
51pub fn median(xs: &[f64]) -> f64 {
53 percentile(xs, 50.0)
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 fn close(a: f64, b: f64, tol: f64) -> bool {
61 (a - b).abs() < tol
62 }
63
64 #[test]
65 fn wilson_ci_matches_reference() {
66 let (lo, hi) = wilson_ci(8, 10);
68 assert!(close(lo, 0.4901, 1e-3), "lo {lo}");
69 assert!(close(hi, 0.9433, 1e-3), "hi {hi}");
70 assert_eq!(wilson_ci(0, 0), (0.0, 0.0));
71 let (lo, hi) = wilson_ci(0, 5);
72 assert_eq!(lo, 0.0);
73 assert!(hi > 0.0 && hi < 1.0);
74 let (lo, hi) = wilson_ci(5, 5);
75 assert!(lo > 0.0 && lo < 1.0);
76 assert_eq!(hi, 1.0);
77 }
78
79 #[test]
80 fn percentile_linear_interpolation() {
81 let xs = [1.0, 2.0, 3.0, 4.0];
82 assert!(close(percentile(&xs, 95.0), 3.85, 1e-12));
83 assert_eq!(percentile(&xs, 0.0), 1.0);
84 assert_eq!(percentile(&xs, 100.0), 4.0);
85 assert_eq!(percentile(&[], 50.0), 0.0);
86 assert_eq!(percentile(&[7.0], 95.0), 7.0);
87 }
88
89 #[test]
90 fn median_odd_even() {
91 assert_eq!(median(&[3.0, 1.0, 2.0]), 2.0);
92 assert_eq!(median(&[4.0, 1.0, 3.0, 2.0]), 2.5);
93 }
94
95 #[test]
96 fn mean_std_basics() {
97 assert_eq!(mean_std(&[]), (0.0, 0.0));
98 assert_eq!(mean_std(&[5.0]), (5.0, 0.0));
99 let (mean, std) = mean_std(&[1.0, 2.0, 3.0]);
100 assert_eq!(mean, 2.0);
101 assert_eq!(std, 1.0);
102 }
103}