1use super::HeaplessBigInt;
9use crate::MachineWord;
10use const_num_traits::{CarryingMul, Ilog, Ilog2, Ilog10, Nct, Zero};
11
12impl<T, const CAP: usize> Ilog2 for HeaplessBigInt<T, CAP, Nct>
13where
14 T: MachineWord,
15{
16 fn ilog2(self) -> u32 {
17 match <Self as Ilog2>::checked_ilog2(self) {
18 Some(v) => v,
19 None => panic!("ilog2: argument is zero"),
20 }
21 }
22
23 fn checked_ilog2(self) -> Option<u32> {
24 if <Self as Zero>::is_zero(&self) {
25 return None;
26 }
27 Some(self.bit_length() as u32 - 1)
29 }
30}
31
32impl<T, const CAP: usize> Ilog10 for HeaplessBigInt<T, CAP, Nct>
33where
34 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
35{
36 fn ilog10(self) -> u32 {
37 match <Self as Ilog10>::checked_ilog10(self) {
38 Some(v) => v,
39 None => panic!("ilog10: argument is zero"),
40 }
41 }
42
43 fn checked_ilog10(self) -> Option<u32> {
44 if <Self as Zero>::is_zero(&self) {
45 return None;
46 }
47 let ten: Self = From::from(10u8);
48 let mut n = self;
49 let mut count = 0u32;
50 while n >= ten {
51 n /= ten;
52 count += 1;
53 }
54 Some(count)
55 }
56}
57
58impl<T, const CAP: usize> Ilog for HeaplessBigInt<T, CAP, Nct>
59where
60 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
61{
62 fn ilog(self, base: Self) -> u32 {
63 match <Self as Ilog>::checked_ilog(self, base) {
64 Some(v) => v,
65 None => panic!("ilog: argument is zero or base is less than 2"),
66 }
67 }
68
69 fn checked_ilog(self, base: Self) -> Option<u32> {
70 if <Self as Zero>::is_zero(&self) {
71 return None;
72 }
73 let two: Self = From::from(2u8);
74 if base < two {
75 return None;
76 }
77 if base == two {
80 return <Self as Ilog2>::checked_ilog2(self);
81 }
82 let ten: Self = From::from(10u8);
83 if base == ten {
84 return <Self as Ilog10>::checked_ilog10(self);
85 }
86 let mut n = self;
87 let mut count = 0u32;
88 while n >= base {
89 n /= base;
90 count += 1;
91 }
92 Some(count)
93 }
94}
95
96impl<T, const CAP: usize> Ilog2 for &HeaplessBigInt<T, CAP, Nct>
98where
99 T: MachineWord,
100{
101 fn ilog2(self) -> u32 {
102 <HeaplessBigInt<T, CAP, Nct> as Ilog2>::ilog2(*self)
103 }
104
105 fn checked_ilog2(self) -> Option<u32> {
106 <HeaplessBigInt<T, CAP, Nct> as Ilog2>::checked_ilog2(*self)
107 }
108}
109
110impl<T, const CAP: usize> Ilog10 for &HeaplessBigInt<T, CAP, Nct>
111where
112 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
113{
114 fn ilog10(self) -> u32 {
115 <HeaplessBigInt<T, CAP, Nct> as Ilog10>::ilog10(*self)
116 }
117
118 fn checked_ilog10(self) -> Option<u32> {
119 <HeaplessBigInt<T, CAP, Nct> as Ilog10>::checked_ilog10(*self)
120 }
121}
122
123impl<T, const CAP: usize> Ilog for &HeaplessBigInt<T, CAP, Nct>
124where
125 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
126{
127 fn ilog(self, base: Self) -> u32 {
128 <HeaplessBigInt<T, CAP, Nct> as Ilog>::ilog(*self, *base)
129 }
130
131 fn checked_ilog(self, base: Self) -> Option<u32> {
132 <HeaplessBigInt<T, CAP, Nct> as Ilog>::checked_ilog(*self, *base)
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::HeaplessBigInt;
139 use const_num_traits::{Ilog, Ilog2, Ilog10};
140
141 type H = HeaplessBigInt<u8, 2>;
142
143 #[test]
144 fn ilog2_values() {
145 for (n, r) in [(1u16, 0u32), (2, 1), (3, 1), (8, 3), (255, 7), (32768, 15)] {
146 assert_eq!(Ilog2::ilog2(H::from(n)), r, "ilog2({n})");
147 }
148 assert_eq!(Ilog2::checked_ilog2(H::from(0u8)), None);
149 }
150
151 #[test]
152 fn ilog10_values() {
153 for (n, r) in [(1u16, 0u32), (9, 0), (10, 1), (999, 2), (10000, 4)] {
154 assert_eq!(Ilog10::ilog10(H::from(n)), r, "ilog10({n})");
155 }
156 assert_eq!(Ilog10::checked_ilog10(H::from(0u8)), None);
157 }
158
159 #[test]
160 fn ilog_base_values() {
161 assert_eq!(Ilog::ilog(H::from(27u8), H::from(3u8)), 3);
162 assert_eq!(Ilog::ilog(H::from(256u16), H::from(16u8)), 2);
163 assert_eq!(Ilog::checked_ilog(H::from(0u8), H::from(2u8)), None);
165 assert_eq!(Ilog::checked_ilog(H::from(10u8), H::from(1u8)), None);
166 }
167
168 #[test]
171 fn ilog_common_base_fast_paths() {
172 for n in [1u16, 2, 3, 8, 255, 1024, 40000] {
173 assert_eq!(
174 Ilog::ilog(H::from(n), H::from(2u8)),
175 Ilog2::ilog2(H::from(n)),
176 "ilog(base 2, {n})"
177 );
178 }
179 for n in [1u16, 9, 10, 99, 1000, 40000] {
180 assert_eq!(
181 Ilog::ilog(H::from(n), H::from(10u8)),
182 Ilog10::ilog10(H::from(n)),
183 "ilog(base 10, {n})"
184 );
185 }
186 }
187
188 #[test]
189 fn byref_matches_value() {
190 let a = H::from(27u8);
191 let base = H::from(3u8);
192 let r = &a; assert_eq!(Ilog2::ilog2(r), Ilog2::ilog2(a));
194 assert_eq!(Ilog2::checked_ilog2(r), Ilog2::checked_ilog2(a));
195 assert_eq!(Ilog10::ilog10(r), Ilog10::ilog10(a));
196 assert_eq!(Ilog10::checked_ilog10(r), Ilog10::checked_ilog10(a));
197 assert_eq!(Ilog::ilog(r, &base), Ilog::ilog(a, base));
198 assert_eq!(Ilog::checked_ilog(r, &base), Ilog::checked_ilog(a, base));
199 }
200}