parry2d/utils/median.rs
1use crate::math::Real;
2
3/// Computes the median of a set of values.
4///
5/// The median is the middle value when the data is sorted. For an even number of values,
6/// it returns the average of the two middle values. This function modifies the input slice
7/// by sorting it in-place.
8///
9/// # Arguments
10///
11/// * `vals` - A mutable slice of values. Must contain at least one value. The slice will be
12/// sorted in-place as a side effect.
13///
14/// # Returns
15///
16/// The median value as a `Real`.
17///
18/// # Panics
19///
20/// Panics if the input slice is empty.
21///
22/// # Examples
23///
24/// ## Odd Number of Values
25///
26/// ```
27/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
28/// use parry2d::math::Real;
29/// use parry2d::utils::median;
30///
31/// let mut values = vec![5.0, 1.0, 3.0, 9.0, 2.0];
32/// let med = median(&mut values);
33///
34/// // With 5 values, the median is the 3rd value when sorted: [1, 2, 3, 5, 9]
35/// assert_eq!(med, 3.0);
36/// # }
37/// ```
38///
39/// ## Even Number of Values
40///
41/// ```
42/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
43/// use parry2d::math::Real;
44/// use parry2d::utils::median;
45///
46/// let mut values = vec![1.0, 2.0, 3.0, 4.0];
47/// let med = median(&mut values);
48///
49/// // With 4 values, median is average of middle two: (2 + 3) / 2 = 2.5
50/// assert_eq!(med, 2.5);
51/// # }
52/// ```
53///
54/// ## Single Value
55///
56/// ```
57/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
58/// use parry2d::math::Real;
59/// use parry2d::utils::median;
60///
61/// let mut values = vec![42.0];
62/// let med = median(&mut values);
63///
64/// // The median of a single value is the value itself
65/// assert_eq!(med, 42.0);
66/// # }
67/// ```
68///
69/// ## Values Are Sorted In-Place
70///
71/// ```
72/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
73/// use parry2d::utils::median;
74///
75/// let mut values = vec![5.0, 1.0, 3.0];
76/// let med = median(&mut values);
77///
78/// // After calling median, the values are sorted
79/// assert_eq!(values, vec![1.0, 3.0, 5.0]);
80/// assert_eq!(med, 3.0);
81/// # }
82/// ```
83#[inline]
84pub fn median(vals: &mut [Real]) -> Real {
85 assert!(
86 !vals.is_empty(),
87 "Cannot compute the median of zero values."
88 );
89
90 vals.sort_by(|a, b| a.partial_cmp(b).unwrap());
91
92 let n = vals.len();
93
94 if n.is_multiple_of(2) {
95 (vals[n / 2 - 1] + vals[n / 2]) / 2.0
96 } else {
97 vals[n / 2]
98 }
99}