1use num::{Integer, PrimInt};
2
3pub fn choose(n: u64, k: u64) -> u64 {
4 if k > n {
5 return 0;
6 }
7
8 if k == 0 || k == n {
9 return 1;
10 }
11
12 let k = if k > n - k { n - k } else { k };
13
14 let mut result = 1;
15 for i in 1..=k {
16 result = result * (n - i + 1) / i;
17 }
18
19 result
20}
21
22pub fn prev_power_of_two<T: PrimInt>(n: T) -> T {
24 if n == T::zero() {
25 return T::zero();
26 }
27 let leading_zeros = n.leading_zeros() as usize;
28 let sizeof = 8 * std::mem::size_of::<T>();
29 T::one() << (sizeof - leading_zeros - 1)
30}
31
32pub fn lsb_index<T: Integer + PrimInt>(n: T) -> Option<u32> {
34 if n == T::zero() {
35 return None;
36 }
37
38 Some(n.trailing_zeros())
39}
40
41pub fn non_zero_lsb_index<T: Integer + PrimInt>(n: T) -> u32 {
43 if n == T::zero() {
44 return 0;
45 }
46
47 n.trailing_zeros()
48}
49
50pub fn horner(x: f64, coefficients: &[f64]) -> f64 {
76 coefficients.iter().fold(0.0, |acc, &coeff| acc * x + coeff)
77}
78
79pub fn zigzag_encode(value: i32) -> u32 {
95 ((value << 1) ^ (value >> 31)) as u32
96}
97
98#[cfg(test)]
99mod tests {
100 use crate::math::{
101 choose, horner, lsb_index, non_zero_lsb_index, prev_power_of_two, zigzag_encode,
102 };
103
104 #[test]
105 fn some_well_known_n_choose_k_values() {
106 let test_cases = [
107 ((64u64, 1u64), 64u64),
108 ((64, 63), 64),
109 ((9, 4), 126),
110 ((10, 5), 252),
111 ((50, 2), 1_225),
112 ((5, 2), 10),
113 ((10, 4), 210),
114 ((37, 17), 15905368710),
115 ((52, 5), 2598960),
116 ];
117
118 test_cases.into_iter().for_each(|((n, k), expected)| {
119 assert_eq!(choose(n, k), expected);
120 });
121 }
122
123 #[test]
124 fn lsb_well_known_values() {
125 assert_eq!(lsb_index(0), None);
126 assert_eq!(lsb_index(10), Some(1));
127 assert_eq!(lsb_index(16), Some(4));
128 assert_eq!(lsb_index(255), Some(0));
129 assert_eq!(lsb_index(1024), Some(10));
130 assert_eq!(lsb_index(72057594037927936_i64), Some(56));
131 }
132
133 #[test]
134 fn lsb_index_well_known_values() {
135 assert_eq!(non_zero_lsb_index(0), 0);
136 assert_eq!(non_zero_lsb_index(10), 1);
137 assert_eq!(non_zero_lsb_index(16), 4);
138 assert_eq!(non_zero_lsb_index(255), 0);
139 assert_eq!(non_zero_lsb_index(1024), 10);
140 assert_eq!(non_zero_lsb_index(72057594037927936_i64), 56);
141 }
142
143 #[test]
144 fn largest_power_of_two_less_or_equal() {
145 assert_eq!(prev_power_of_two(16_u8), 16);
146 assert_eq!(prev_power_of_two(17_i32), 16);
147 assert_eq!(prev_power_of_two(0x5555555555555_u64), 0x4000000000000)
148 }
149
150 #[test]
151 fn test_horner1() {
152 let coefficients = [2.0, 3.0, 1.0];
154 assert_eq!(horner(0.0, &coefficients), 1.0);
155 assert_eq!(horner(1.0, &coefficients), 6.0);
156 assert_eq!(horner(2.0, &coefficients), 15.0);
157 }
158
159 #[test]
160 fn test_horner2() {
161 let coefficients = [1.0, -2.0, 3.0, -4.0];
163 assert!((horner(0.0, &coefficients) - (-4.0)).abs() < 1e-10);
164 assert!((horner(1.0, &coefficients) - (-2.0)).abs() < 1e-10);
165 assert!((horner(2.0, &coefficients) - 2.0).abs() < 1e-10);
166 }
167
168 #[test]
169 fn test_horner3() {
170 assert_eq!(horner(1.0, &[]), 0.0);
172 }
173
174 #[test]
175 fn test_horner4() {
176 assert_eq!(horner(42.0, &[5.0]), 5.0);
178 }
179
180 #[test]
181 fn test_zigzag_encode() {
182 assert_eq!(zigzag_encode(0), 0);
183 assert_eq!(zigzag_encode(-1), 1);
184 assert_eq!(zigzag_encode(1), 2);
185 assert_eq!(zigzag_encode(-2), 3);
186 assert_eq!(zigzag_encode(i32::MIN), u32::MAX);
187 }
188}