1#![deny(unsafe_code)]
7#![warn(rust_2018_idioms)]
8#![warn(missing_docs)]
9#![warn(clippy::all)]
10
11#[must_use]
28pub fn nearest_rank_percentile(sorted_values: &[u64], pct: u64) -> u64 {
29 if sorted_values.is_empty() {
30 return 0;
31 }
32
33 let pct_clamped = pct.min(100);
34 let rank = ((pct_clamped as f64 / 100.0) * sorted_values.len() as f64).ceil() as usize;
35 sorted_values[rank.min(sorted_values.len()).saturating_sub(1)]
36}
37
38#[cfg(test)]
39mod tests {
40 use super::nearest_rank_percentile;
41
42 #[test]
43 fn nearest_rank_handles_empty_input() {
44 assert_eq!(nearest_rank_percentile(&[], 95), 0);
45 }
46
47 #[test]
48 fn nearest_rank_percentiles_match_expected_values() {
49 let sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
50 assert_eq!(nearest_rank_percentile(&sorted, 50), 5);
51 assert_eq!(nearest_rank_percentile(&sorted, 95), 10);
52 assert_eq!(nearest_rank_percentile(&sorted, 99), 10);
53 }
54
55 #[test]
56 fn nearest_rank_clamps_high_percentiles() {
57 let sorted = [10, 20, 30];
58 assert_eq!(nearest_rank_percentile(&sorted, 1000), 30);
59 }
60}