1#![allow(clippy::manual_range_contains)] use super::{biguint_from_vec, fls, ilog2, BigUint, ToBigUint};
5
6use super::addition::add2;
7use super::division::{div_rem_digit, FAST_DIV_WIDE};
8use super::multiplication::mac_with_carry;
9
10use crate::big_digit::{self, BigDigit, BigDigits};
11use crate::ParseBigIntError;
12use crate::TryFromBigIntError;
13
14use alloc::vec::Vec;
15use core::cmp::Ordering::{Equal, Greater, Less};
16use core::convert::TryFrom;
17use core::str::FromStr;
18use num_integer::Integer;
19use num_traits::float::FloatCore;
20use num_traits::{FromPrimitive, Num, ToPrimitive, Zero};
21
22impl FromStr for BigUint {
23 type Err = ParseBigIntError;
24
25 #[inline]
26 fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> {
27 BigUint::from_str_radix(s, 10)
28 }
29}
30
31pub(super) fn from_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
34 debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits == 0);
35 debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
36
37 let digits_per_big_digit = big_digit::BITS / bits;
38
39 let data = v
40 .chunks(digits_per_big_digit.into())
41 .map(|chunk| {
42 chunk
43 .iter()
44 .rev()
45 .fold(0, |acc, &c| (acc << bits) | BigDigit::from(c))
46 })
47 .collect();
48
49 biguint_from_vec(data)
50}
51
52fn from_inexact_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
55 debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits != 0);
56 debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
57
58 let total_bits = (v.len() as u64).saturating_mul(bits.into());
59 let big_digits = Integer::div_ceil(&total_bits, &big_digit::BITS.into())
60 .to_usize()
61 .unwrap_or(usize::MAX);
62 let mut data = Vec::with_capacity(big_digits);
63
64 let mut d = 0;
65 let mut dbits = 0; for &c in v {
70 d |= BigDigit::from(c) << dbits;
71 dbits += bits;
72
73 if dbits >= big_digit::BITS {
74 data.push(d);
75 dbits -= big_digit::BITS;
76 d = BigDigit::from(c) >> (bits - dbits);
79 }
80 }
81
82 if dbits > 0 {
83 debug_assert!(dbits < big_digit::BITS);
84 data.push(d as BigDigit);
85 }
86
87 biguint_from_vec(data)
88}
89
90fn from_radix_digits_be(v: &[u8], radix: u32) -> BigUint {
92 debug_assert!(!v.is_empty() && !radix.is_power_of_two());
93 debug_assert!(v.iter().all(|&c| u32::from(c) < radix));
94
95 #[cfg(feature = "std")]
97 let big_digits = {
98 let radix_log2 = f64::from(radix).log2();
99 let bits = radix_log2 * v.len() as f64;
100 (bits / big_digit::BITS as f64).ceil()
101 };
102 #[cfg(not(feature = "std"))]
103 let big_digits = {
104 let radix_log2 = ilog2(radix.next_power_of_two()) as usize;
105 let bits = radix_log2 * v.len();
106 (bits / big_digit::BITS as usize) + 1
107 };
108
109 let mut data = Vec::with_capacity(big_digits.to_usize().unwrap_or(0));
110
111 let (base, power) = get_radix_base(radix);
112 let radix = radix as BigDigit;
113
114 let r = v.len() % power;
115 let i = if r == 0 { power } else { r };
116 let (head, tail) = v.split_at(i);
117
118 let first = head
119 .iter()
120 .fold(0, |acc, &d| acc * radix + BigDigit::from(d));
121 data.push(first);
122
123 debug_assert!(tail.len() % power == 0);
124 for chunk in tail.chunks(power) {
125 if data.last() != Some(&0) {
126 data.push(0);
127 }
128
129 let mut carry = 0;
130 for d in data.iter_mut() {
131 *d = mac_with_carry(0, *d, base, &mut carry);
132 }
133 debug_assert!(carry == 0);
134
135 let n = chunk
136 .iter()
137 .fold(0, |acc, &d| acc * radix + BigDigit::from(d));
138 add2(&mut data, &[n]);
139 }
140
141 biguint_from_vec(data)
142}
143
144pub(super) fn from_radix_be(buf: &[u8], radix: u32) -> Option<BigUint> {
145 assert!(
146 2 <= radix && radix <= 256,
147 "The radix must be within 2...256"
148 );
149
150 if buf.is_empty() {
151 return Some(BigUint::ZERO);
152 }
153
154 if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
155 return None;
156 }
157
158 let res = if radix.is_power_of_two() {
159 let bits = ilog2(radix);
161 let mut v = Vec::from(buf);
162 v.reverse();
163 if big_digit::BITS % bits == 0 {
164 from_bitwise_digits_le(&v, bits)
165 } else {
166 from_inexact_bitwise_digits_le(&v, bits)
167 }
168 } else {
169 from_radix_digits_be(buf, radix)
170 };
171
172 Some(res)
173}
174
175pub(super) fn from_radix_le(buf: &[u8], radix: u32) -> Option<BigUint> {
176 assert!(
177 2 <= radix && radix <= 256,
178 "The radix must be within 2...256"
179 );
180
181 if buf.is_empty() {
182 return Some(BigUint::ZERO);
183 }
184
185 if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
186 return None;
187 }
188
189 let res = if radix.is_power_of_two() {
190 let bits = ilog2(radix);
192 if big_digit::BITS % bits == 0 {
193 from_bitwise_digits_le(buf, bits)
194 } else {
195 from_inexact_bitwise_digits_le(buf, bits)
196 }
197 } else {
198 let mut v = Vec::from(buf);
199 v.reverse();
200 from_radix_digits_be(&v, radix)
201 };
202
203 Some(res)
204}
205
206impl Num for BigUint {
207 type FromStrRadixErr = ParseBigIntError;
208
209 fn from_str_radix(s: &str, radix: u32) -> Result<BigUint, ParseBigIntError> {
211 assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
212 let mut s = s;
213 if let Some(tail) = s.strip_prefix('+') {
214 if !tail.starts_with('+') {
215 s = tail
216 }
217 }
218
219 if s.is_empty() {
220 return Err(ParseBigIntError::empty());
221 }
222
223 if s.starts_with('_') {
224 return Err(ParseBigIntError::invalid());
226 }
227
228 let mut v = Vec::with_capacity(s.len());
230 for b in s.bytes() {
231 let d = match b {
232 b'0'..=b'9' => b - b'0',
233 b'a'..=b'z' => b - b'a' + 10,
234 b'A'..=b'Z' => b - b'A' + 10,
235 b'_' => continue,
236 _ => u8::MAX,
237 };
238 if d < radix as u8 {
239 v.push(d);
240 } else {
241 return Err(ParseBigIntError::invalid());
242 }
243 }
244
245 let res = if radix.is_power_of_two() {
246 let bits = ilog2(radix);
248 v.reverse();
249 if big_digit::BITS % bits == 0 {
250 from_bitwise_digits_le(&v, bits)
251 } else {
252 from_inexact_bitwise_digits_le(&v, bits)
253 }
254 } else {
255 from_radix_digits_be(&v, radix)
256 };
257 Ok(res)
258 }
259}
260
261fn high_bits_to_u64(v: &BigUint) -> u64 {
262 match v.data.len() {
263 0 => 0,
264 1 => {
265 #[allow(clippy::useless_conversion)]
267 let v0 = u64::from(v.data[0]);
268 v0
269 }
270 _ => {
271 let mut bits = v.bits();
272 let mut ret = 0u64;
273 let mut ret_bits = 0;
274
275 for d in v.data.iter().rev() {
276 let digit_bits = (bits - 1) % u64::from(big_digit::BITS) + 1;
277 let bits_want = Ord::min(64 - ret_bits, digit_bits);
278
279 if bits_want != 0 {
280 if bits_want != 64 {
281 ret <<= bits_want;
282 }
283 #[allow(clippy::useless_conversion)]
285 let d0 = u64::from(*d) >> (digit_bits - bits_want);
286 ret |= d0;
287 }
288
289 if digit_bits - bits_want != 0 {
296 #[allow(clippy::useless_conversion)]
298 let masked = u64::from(*d) << (64 - (digit_bits - bits_want) as u32);
299 ret |= (masked != 0) as u64;
300 }
301
302 ret_bits += bits_want;
303 bits -= bits_want;
304 }
305
306 ret
307 }
308 }
309}
310
311impl ToPrimitive for BigUint {
312 #[inline]
313 fn to_i64(&self) -> Option<i64> {
314 self.to_u64().as_ref().and_then(u64::to_i64)
315 }
316
317 #[inline]
318 fn to_i128(&self) -> Option<i128> {
319 self.to_u128().as_ref().and_then(u128::to_i128)
320 }
321
322 #[allow(clippy::useless_conversion)]
323 #[inline]
324 fn to_u64(&self) -> Option<u64> {
325 let mut ret: u64 = 0;
326 let mut bits = 0;
327
328 for i in self.data.iter() {
329 if bits >= 64 {
330 return None;
331 }
332
333 ret += u64::from(*i) << bits;
335 bits += big_digit::BITS;
336 }
337
338 Some(ret)
339 }
340
341 #[inline]
342 fn to_u128(&self) -> Option<u128> {
343 let mut ret: u128 = 0;
344 let mut bits = 0;
345
346 for i in self.data.iter() {
347 if bits >= 128 {
348 return None;
349 }
350
351 ret |= u128::from(*i) << bits;
352 bits += big_digit::BITS;
353 }
354
355 Some(ret)
356 }
357
358 #[inline]
359 fn to_f32(&self) -> Option<f32> {
360 let mantissa = high_bits_to_u64(self);
361 let exponent = self.bits() - u64::from(fls(mantissa));
362
363 if exponent > f32::MAX_EXP as u64 {
364 Some(f32::INFINITY)
365 } else {
366 Some((mantissa as f32) * 2.0f32.powi(exponent as i32))
367 }
368 }
369
370 #[inline]
371 fn to_f64(&self) -> Option<f64> {
372 let mantissa = high_bits_to_u64(self);
373 let exponent = self.bits() - u64::from(fls(mantissa));
374
375 if exponent > f64::MAX_EXP as u64 {
376 Some(f64::INFINITY)
377 } else {
378 Some((mantissa as f64) * 2.0f64.powi(exponent as i32))
379 }
380 }
381}
382
383macro_rules! impl_try_from_biguint {
384 ($T:ty, $to_ty:path) => {
385 impl TryFrom<&BigUint> for $T {
386 type Error = TryFromBigIntError<()>;
387
388 #[inline]
389 fn try_from(value: &BigUint) -> Result<$T, TryFromBigIntError<()>> {
390 $to_ty(value).ok_or(TryFromBigIntError::new(()))
391 }
392 }
393
394 impl TryFrom<BigUint> for $T {
395 type Error = TryFromBigIntError<BigUint>;
396
397 #[inline]
398 fn try_from(value: BigUint) -> Result<$T, TryFromBigIntError<BigUint>> {
399 <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
400 }
401 }
402 };
403}
404
405impl_try_from_biguint!(u8, ToPrimitive::to_u8);
406impl_try_from_biguint!(u16, ToPrimitive::to_u16);
407impl_try_from_biguint!(u32, ToPrimitive::to_u32);
408impl_try_from_biguint!(u64, ToPrimitive::to_u64);
409impl_try_from_biguint!(usize, ToPrimitive::to_usize);
410impl_try_from_biguint!(u128, ToPrimitive::to_u128);
411
412impl_try_from_biguint!(i8, ToPrimitive::to_i8);
413impl_try_from_biguint!(i16, ToPrimitive::to_i16);
414impl_try_from_biguint!(i32, ToPrimitive::to_i32);
415impl_try_from_biguint!(i64, ToPrimitive::to_i64);
416impl_try_from_biguint!(isize, ToPrimitive::to_isize);
417impl_try_from_biguint!(i128, ToPrimitive::to_i128);
418
419impl FromPrimitive for BigUint {
420 #[inline]
421 fn from_i64(n: i64) -> Option<BigUint> {
422 if n >= 0 {
423 Some(BigUint::from(n as u64))
424 } else {
425 None
426 }
427 }
428
429 #[inline]
430 fn from_i128(n: i128) -> Option<BigUint> {
431 if n >= 0 {
432 Some(BigUint::from(n as u128))
433 } else {
434 None
435 }
436 }
437
438 #[inline]
439 fn from_u64(n: u64) -> Option<BigUint> {
440 Some(BigUint::from(n))
441 }
442
443 #[inline]
444 fn from_u128(n: u128) -> Option<BigUint> {
445 Some(BigUint::from(n))
446 }
447
448 #[inline]
449 fn from_f64(mut n: f64) -> Option<BigUint> {
450 if !n.is_finite() {
452 return None;
453 }
454
455 n = n.trunc();
457
458 if n.is_zero() {
460 return Some(Self::ZERO);
461 }
462
463 let (mantissa, exponent, sign) = FloatCore::integer_decode(n);
464
465 if sign == -1 {
466 return None;
467 }
468
469 let mut ret = BigUint::from(mantissa);
470 match exponent.cmp(&0) {
471 Greater => ret <<= exponent as usize,
472 Equal => {}
473 Less => ret >>= (-exponent) as usize,
474 }
475 Some(ret)
476 }
477}
478
479impl From<u8> for BigUint {
480 #[inline]
481 fn from(n: u8) -> Self {
482 BigUint::from(u32::from(n))
483 }
484}
485
486impl From<u16> for BigUint {
487 #[inline]
488 fn from(n: u16) -> Self {
489 BigUint::from(u32::from(n))
490 }
491}
492
493impl From<u32> for BigUint {
494 #[inline]
495 fn from(n: u32) -> Self {
496 BigUint {
497 data: BigDigits::from_digit(n as BigDigit),
498 }
499 }
500}
501
502impl From<u64> for BigUint {
503 #[inline]
504 fn from(n: u64) -> Self {
505 cfg_digit_expr!(
506 return if n > big_digit::MAX as u64 {
507 BigUint::new(vec![n as BigDigit, (n >> big_digit::BITS) as BigDigit])
508 } else {
509 BigUint {
510 data: BigDigits::from_digit(n as BigDigit),
511 }
512 },
513 return BigUint {
514 data: BigDigits::from_digit(n),
515 }
516 );
517 }
518}
519
520impl From<u128> for BigUint {
521 #[inline]
522 fn from(mut n: u128) -> Self {
523 let mut ret: BigUint = Self::ZERO;
524
525 while n != 0 {
526 ret.data.push(n as BigDigit);
527 n >>= big_digit::BITS;
528 }
529
530 ret
531 }
532}
533
534impl From<usize> for BigUint {
535 #[inline]
536 fn from(n: usize) -> Self {
537 BigUint::from(n as crate::UsizePromotion)
538 }
539}
540
541macro_rules! impl_biguint_try_from_int {
542 ($T:ty, $from_ty:path) => {
543 impl TryFrom<$T> for BigUint {
544 type Error = TryFromBigIntError<()>;
545
546 #[inline]
547 fn try_from(value: $T) -> Result<BigUint, TryFromBigIntError<()>> {
548 $from_ty(value).ok_or(TryFromBigIntError::new(()))
549 }
550 }
551 };
552}
553
554impl_biguint_try_from_int!(i8, FromPrimitive::from_i8);
555impl_biguint_try_from_int!(i16, FromPrimitive::from_i16);
556impl_biguint_try_from_int!(i32, FromPrimitive::from_i32);
557impl_biguint_try_from_int!(i64, FromPrimitive::from_i64);
558impl_biguint_try_from_int!(isize, FromPrimitive::from_isize);
559impl_biguint_try_from_int!(i128, FromPrimitive::from_i128);
560
561impl ToBigUint for BigUint {
562 #[inline]
563 fn to_biguint(&self) -> Option<BigUint> {
564 Some(self.clone())
565 }
566}
567
568macro_rules! impl_to_biguint {
569 ($T:ty, $from_ty:path) => {
570 impl ToBigUint for $T {
571 #[inline]
572 fn to_biguint(&self) -> Option<BigUint> {
573 $from_ty(*self)
574 }
575 }
576 };
577}
578
579impl_to_biguint!(isize, FromPrimitive::from_isize);
580impl_to_biguint!(i8, FromPrimitive::from_i8);
581impl_to_biguint!(i16, FromPrimitive::from_i16);
582impl_to_biguint!(i32, FromPrimitive::from_i32);
583impl_to_biguint!(i64, FromPrimitive::from_i64);
584impl_to_biguint!(i128, FromPrimitive::from_i128);
585
586impl_to_biguint!(usize, FromPrimitive::from_usize);
587impl_to_biguint!(u8, FromPrimitive::from_u8);
588impl_to_biguint!(u16, FromPrimitive::from_u16);
589impl_to_biguint!(u32, FromPrimitive::from_u32);
590impl_to_biguint!(u64, FromPrimitive::from_u64);
591impl_to_biguint!(u128, FromPrimitive::from_u128);
592
593impl_to_biguint!(f32, FromPrimitive::from_f32);
594impl_to_biguint!(f64, FromPrimitive::from_f64);
595
596impl From<bool> for BigUint {
597 fn from(x: bool) -> Self {
598 if x {
599 Self::ONE
600 } else {
601 Self::ZERO
602 }
603 }
604}
605
606pub(super) fn to_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
608 debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits == 0);
609
610 let last_i = u.data.len() - 1;
611 let mask: BigDigit = (1 << bits) - 1;
612 let digits_per_big_digit = big_digit::BITS / bits;
613 let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
614 .to_usize()
615 .unwrap_or(usize::MAX);
616 let mut res = Vec::with_capacity(digits);
617
618 for mut r in u.data[..last_i].iter().cloned() {
619 for _ in 0..digits_per_big_digit {
620 res.push((r & mask) as u8);
621 r >>= bits;
622 }
623 }
624
625 let mut r = u.data[last_i];
626 while r != 0 {
627 res.push((r & mask) as u8);
628 r >>= bits;
629 }
630
631 res
632}
633
634fn to_inexact_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
636 debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits != 0);
637
638 let mask: BigDigit = (1 << bits) - 1;
639 let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
640 .to_usize()
641 .unwrap_or(usize::MAX);
642 let mut res = Vec::with_capacity(digits);
643
644 let mut r = 0;
645 let mut rbits = 0;
646
647 for c in &*u.data {
648 r |= *c << rbits;
649 rbits += big_digit::BITS;
650
651 while rbits >= bits {
652 res.push((r & mask) as u8);
653 r >>= bits;
654
655 if rbits > big_digit::BITS {
657 r = *c >> (big_digit::BITS - (rbits - bits));
658 }
659
660 rbits -= bits;
661 }
662 }
663
664 if rbits != 0 {
665 res.push(r as u8);
666 }
667
668 while let Some(&0) = res.last() {
669 res.pop();
670 }
671
672 res
673}
674
675#[inline(always)] pub(super) fn to_radix_digits_le(u: &BigUint, radix: u32) -> Vec<u8> {
678 debug_assert!(!u.is_zero() && !radix.is_power_of_two());
679
680 #[cfg(feature = "std")]
681 let radix_digits = {
682 let radix_log2 = f64::from(radix).log2();
683 ((u.bits() as f64) / radix_log2).ceil()
684 };
685 #[cfg(not(feature = "std"))]
686 let radix_digits = {
687 let radix_log2 = ilog2(radix) as usize;
688 ((u.bits() as usize) / radix_log2) + 1
689 };
690
691 let mut res = Vec::with_capacity(radix_digits.to_usize().unwrap_or(0));
693
694 let digits = u.clone();
695
696 let (base, power) = if FAST_DIV_WIDE {
699 get_radix_base(radix)
700 } else {
701 get_half_radix_base(radix)
702 };
703 let radix = radix as BigDigit;
704
705 if digits.data.len() >= 32 {
710 let mut big_bases = Vec::with_capacity(32);
711 big_bases.push((BigUint::from(base), power));
712
713 loop {
714 let (big_base, power) = big_bases.last().unwrap();
715 if big_base.data.len() > digits.data.len() / 2 + 1 {
716 break;
717 }
718 let next_big_base = big_base * big_base;
719 let next_power = *power * 2;
720 big_bases.push((next_big_base, next_power));
721 }
722
723 to_radix_digits_le_divide_and_conquer(
724 digits,
725 base,
726 power,
727 &big_bases,
728 big_bases.len() - 1,
729 &mut res,
730 radix,
731 );
732 while res.last() == Some(&0) {
733 res.pop();
734 }
735 return res;
736 }
737
738 to_radix_digits_le_small(digits, base, power, &mut res, radix);
739
740 res
741}
742
743#[inline(always)] fn to_radix_digits_le_small(
746 mut digits: BigUint,
747 base: BigDigit,
748 power: usize,
749 res: &mut Vec<u8>,
750 radix: BigDigit,
751) {
752 while digits.data.len() > 1 {
753 let (q, mut r) = div_rem_digit(digits, base);
754 for _ in 0..power {
755 res.push((r % radix) as u8);
756 r /= radix;
757 }
758 digits = q;
759 }
760
761 let mut r = digits.data[0];
762 while r != 0 {
763 res.push((r % radix) as u8);
764 r /= radix;
765 }
766}
767
768fn to_radix_digits_le_divide_and_conquer(
769 number: BigUint,
770 base: BigDigit,
771 power: usize,
772 big_bases: &[(BigUint, usize)],
773 k: usize,
774 res: &mut Vec<u8>,
775 radix: BigDigit,
776) {
777 let &(ref big_base, result_len) = &big_bases[k];
778 if number.data.len() < 8 {
779 let prev_res_len = res.len();
780 if !number.is_zero() {
781 to_radix_digits_le_small(number, base, power, res, radix);
782 }
783 while res.len() < prev_res_len + result_len * 2 {
784 res.push(0);
785 }
786 return;
787 }
788 let (digit_1, digit_2) = number.div_rem(big_base);
790 assert!(&digit_1 < big_base);
791 assert!(&digit_2 < big_base);
792 to_radix_digits_le_divide_and_conquer(digit_2, base, power, big_bases, k - 1, res, radix);
793 to_radix_digits_le_divide_and_conquer(digit_1, base, power, big_bases, k - 1, res, radix);
794}
795
796pub(super) fn to_radix_le(u: &BigUint, radix: u32) -> Vec<u8> {
797 if u.is_zero() {
798 vec![0]
799 } else if radix.is_power_of_two() {
800 let bits = ilog2(radix);
802 if big_digit::BITS % bits == 0 {
803 to_bitwise_digits_le(u, bits)
804 } else {
805 to_inexact_bitwise_digits_le(u, bits)
806 }
807 } else if radix == 10 {
808 to_radix_digits_le(u, 10)
811 } else {
812 to_radix_digits_le(u, radix)
813 }
814}
815
816pub(crate) fn to_str_radix_reversed(u: &BigUint, radix: u32) -> Vec<u8> {
817 assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
818
819 if u.is_zero() {
820 return vec![b'0'];
821 }
822
823 let mut res = to_radix_le(u, radix);
824
825 for r in &mut res {
827 debug_assert!(u32::from(*r) < radix);
828 if *r < 10 {
829 *r += b'0';
830 } else {
831 *r += b'a' - 10;
832 }
833 }
834 res
835}
836
837#[inline]
839fn get_radix_base(radix: u32) -> (BigDigit, usize) {
840 static BASES: [(BigDigit, usize); 257] = generate_radix_bases(big_digit::MAX);
841 debug_assert!(!radix.is_power_of_two());
842 debug_assert!((3..256).contains(&radix));
843 BASES[radix as usize]
844}
845
846#[inline]
848fn get_half_radix_base(radix: u32) -> (BigDigit, usize) {
849 static BASES: [(BigDigit, usize); 257] = generate_radix_bases(big_digit::HALF);
850 debug_assert!(!radix.is_power_of_two());
851 debug_assert!((3..256).contains(&radix));
852 BASES[radix as usize]
853}
854
855const fn generate_radix_bases(max: BigDigit) -> [(BigDigit, usize); 257] {
865 let mut bases = [(0, 0); 257];
866
867 let mut radix: BigDigit = 3;
868 while radix < 256 {
869 if !radix.is_power_of_two() {
870 let mut power = 1;
871 let mut base = radix;
872
873 while let Some(b) = base.checked_mul(radix) {
874 if b > max {
875 break;
876 }
877 base = b;
878 power += 1;
879 }
880 bases[radix as usize] = (base, power)
881 }
882 radix += 1;
883 }
884
885 bases
886}
887
888#[test]
889fn test_radix_bases() {
890 for radix in 3u32..256 {
891 if !radix.is_power_of_two() {
892 let (base, power) = get_radix_base(radix);
893 let radix = BigDigit::from(radix);
894 let power = u32::try_from(power).unwrap();
895 assert_eq!(base, radix.pow(power));
896 assert!(radix.checked_pow(power + 1).is_none());
897 }
898 }
899}
900
901#[test]
902fn test_half_radix_bases() {
903 for radix in 3u32..256 {
904 if !radix.is_power_of_two() {
905 let (base, power) = get_half_radix_base(radix);
906 let radix = BigDigit::from(radix);
907 let power = u32::try_from(power).unwrap();
908 assert_eq!(base, radix.pow(power));
909 assert!(radix.pow(power + 1) > big_digit::HALF);
910 }
911 }
912}