atcoder/lib/math/
radix.rs1pub fn to_digits(mut value: usize, base: usize) -> Vec<usize> {
23 assert!(base >= 2, "base must be at least 2");
24
25 if value == 0 {
26 return vec![0];
27 }
28
29 let mut digits = Vec::new();
30 while value > 0 {
31 digits.push(value % base);
32 value /= base;
33 }
34 digits.reverse();
35 digits
36}
37
38pub fn to_bijective_digits(mut value: usize, base: usize) -> Vec<usize> {
58 assert!(base >= 2, "base must be at least 2");
59 assert!(value >= 1, "value must be positive");
60
61 let mut digits = Vec::new();
62 while value > 0 {
63 value -= 1;
64 digits.push(value % base);
65 value /= base;
66 }
67 digits.reverse();
68 digits
69}
70
71pub fn from_digits(digits: &[usize], base: usize) -> Option<usize> {
90 assert!(base >= 2, "base must be at least 2");
91
92 if digits.is_empty() {
93 return None;
94 }
95
96 digits.iter().try_fold(0_usize, |value, &digit| {
97 if digit >= base {
98 return None;
99 }
100 value.checked_mul(base)?.checked_add(digit)
101 })
102}
103
104#[cfg(test)]
105mod tests {
106 use super::{from_digits, to_bijective_digits, to_digits};
107
108 #[test]
109 fn converts_values_to_digits() {
110 assert_eq!(to_digits(0, 2), vec![0]);
111 assert_eq!(to_digits(13, 2), vec![1, 1, 0, 1]);
112 assert_eq!(to_digits(255, 16), vec![15, 15]);
113 assert_eq!(to_digits(26, 26), vec![1, 0]);
114 }
115
116 #[test]
117 fn converts_values_to_bijective_digits() {
118 assert_eq!(to_bijective_digits(1, 26), vec![0]);
119 assert_eq!(to_bijective_digits(26, 26), vec![25]);
120 assert_eq!(to_bijective_digits(27, 26), vec![0, 0]);
121 assert_eq!(to_bijective_digits(28, 26), vec![0, 1]);
122 assert_eq!(
123 to_bijective_digits(usize::MAX, usize::MAX),
124 vec![usize::MAX - 1]
125 );
126 }
127
128 #[test]
129 fn converts_digits_to_values() {
130 assert_eq!(from_digits(&[0], 2), Some(0));
131 assert_eq!(from_digits(&[1, 1, 0, 1], 2), Some(13));
132 assert_eq!(from_digits(&[15, 15], 16), Some(255));
133 assert_eq!(from_digits(&[0, 0, 1], 10), Some(1));
134 }
135
136 #[test]
137 fn round_trips_values() {
138 for base in [2, 3, 10, 16, 26, usize::MAX] {
139 for value in [0, 1, 25, 26, 255, usize::MAX] {
140 assert_eq!(from_digits(&to_digits(value, base), base), Some(value));
141 }
142 }
143 }
144
145 #[test]
146 fn rejects_empty_invalid_or_overflowing_digits() {
147 assert_eq!(from_digits(&[], 10), None);
148 assert_eq!(from_digits(&[1, 2], 2), None);
149 assert_eq!(from_digits(&[usize::MAX], usize::MAX), None);
150 assert_eq!(from_digits(&[1, 1], usize::MAX), None);
151 }
152
153 #[test]
154 #[should_panic(expected = "base must be at least 2")]
155 fn rejects_invalid_base_when_encoding() {
156 to_digits(10, 1);
157 }
158
159 #[test]
160 #[should_panic(expected = "value must be positive")]
161 fn rejects_zero_when_bijective_encoding() {
162 to_bijective_digits(0, 26);
163 }
164
165 #[test]
166 #[should_panic(expected = "base must be at least 2")]
167 fn rejects_invalid_base_when_decoding() {
168 from_digits(&[1], 1);
169 }
170}