num_bigint/biguint/
convert.rs

1use super::{biguint_from_vec, BigUint, ToBigUint};
2
3use super::addition::add2;
4use super::division::div_rem_digit;
5use super::multiplication::mac_with_carry;
6
7use crate::big_digit::{self, BigDigit};
8use crate::std_alloc::Vec;
9use crate::ParseBigIntError;
10#[cfg(has_try_from)]
11use crate::TryFromBigIntError;
12
13use core::cmp::Ordering::{Equal, Greater, Less};
14#[cfg(has_try_from)]
15use core::convert::TryFrom;
16use core::mem;
17use core::str::FromStr;
18use num_integer::{Integer, Roots};
19use num_traits::float::FloatCore;
20use num_traits::{FromPrimitive, Num, PrimInt, ToPrimitive, Zero};
21
22/// Find last set bit
23/// fls(0) == 0, fls(u32::MAX) == 32
24fn fls<T: PrimInt>(v: T) -> u8 {
25    mem::size_of::<T>() as u8 * 8 - v.leading_zeros() as u8
26}
27
28fn ilog2<T: PrimInt>(v: T) -> u8 {
29    fls(v) - 1
30}
31
32impl FromStr for BigUint {
33    type Err = ParseBigIntError;
34
35    #[inline]
36    fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> {
37        BigUint::from_str_radix(s, 10)
38    }
39}
40
41// Convert from a power of two radix (bits == ilog2(radix)) where bits evenly divides
42// BigDigit::BITS
43pub(super) fn from_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
44    debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits == 0);
45    debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
46
47    let digits_per_big_digit = big_digit::BITS / bits;
48
49    let data = v
50        .chunks(digits_per_big_digit.into())
51        .map(|chunk| {
52            chunk
53                .iter()
54                .rev()
55                .fold(0, |acc, &c| (acc << bits) | BigDigit::from(c))
56        })
57        .collect();
58
59    biguint_from_vec(data)
60}
61
62// Convert from a power of two radix (bits == ilog2(radix)) where bits doesn't evenly divide
63// BigDigit::BITS
64fn from_inexact_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
65    debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits != 0);
66    debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
67
68    let total_bits = (v.len() as u64).saturating_mul(bits.into());
69    let big_digits = Integer::div_ceil(&total_bits, &big_digit::BITS.into())
70        .to_usize()
71        .unwrap_or(core::usize::MAX);
72    let mut data = Vec::with_capacity(big_digits);
73
74    let mut d = 0;
75    let mut dbits = 0; // number of bits we currently have in d
76
77    // walk v accumululating bits in d; whenever we accumulate big_digit::BITS in d, spit out a
78    // big_digit:
79    for &c in v {
80        d |= BigDigit::from(c) << dbits;
81        dbits += bits;
82
83        if dbits >= big_digit::BITS {
84            data.push(d);
85            dbits -= big_digit::BITS;
86            // if dbits was > big_digit::BITS, we dropped some of the bits in c (they couldn't fit
87            // in d) - grab the bits we lost here:
88            d = BigDigit::from(c) >> (bits - dbits);
89        }
90    }
91
92    if dbits > 0 {
93        debug_assert!(dbits < big_digit::BITS);
94        data.push(d as BigDigit);
95    }
96
97    biguint_from_vec(data)
98}
99
100// Read little-endian radix digits
101fn from_radix_digits_be(v: &[u8], radix: u32) -> BigUint {
102    debug_assert!(!v.is_empty() && !radix.is_power_of_two());
103    debug_assert!(v.iter().all(|&c| u32::from(c) < radix));
104
105    #[cfg(feature = "std")]
106    let radix_log2 = f64::from(radix).log2();
107    #[cfg(not(feature = "std"))]
108    let radix_log2 = ilog2(radix.next_power_of_two()) as f64;
109
110    // Estimate how big the result will be, so we can pre-allocate it.
111    let bits = radix_log2 * v.len() as f64;
112    let big_digits = (bits / big_digit::BITS as f64).ceil();
113    let mut data = Vec::with_capacity(big_digits.to_usize().unwrap_or(0));
114
115    let (base, power) = get_radix_base(radix, big_digit::BITS);
116    let radix = radix as BigDigit;
117
118    let r = v.len() % power;
119    let i = if r == 0 { power } else { r };
120    let (head, tail) = v.split_at(i);
121
122    let first = head
123        .iter()
124        .fold(0, |acc, &d| acc * radix + BigDigit::from(d));
125    data.push(first);
126
127    debug_assert!(tail.len() % power == 0);
128    for chunk in tail.chunks(power) {
129        if data.last() != Some(&0) {
130            data.push(0);
131        }
132
133        let mut carry = 0;
134        for d in data.iter_mut() {
135            *d = mac_with_carry(0, *d, base, &mut carry);
136        }
137        debug_assert!(carry == 0);
138
139        let n = chunk
140            .iter()
141            .fold(0, |acc, &d| acc * radix + BigDigit::from(d));
142        add2(&mut data, &[n]);
143    }
144
145    biguint_from_vec(data)
146}
147
148pub(super) fn from_radix_be(buf: &[u8], radix: u32) -> Option<BigUint> {
149    assert!(
150        2 <= radix && radix <= 256,
151        "The radix must be within 2...256"
152    );
153
154    if buf.is_empty() {
155        return Some(Zero::zero());
156    }
157
158    if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
159        return None;
160    }
161
162    let res = if radix.is_power_of_two() {
163        // Powers of two can use bitwise masks and shifting instead of multiplication
164        let bits = ilog2(radix);
165        let mut v = Vec::from(buf);
166        v.reverse();
167        if big_digit::BITS % bits == 0 {
168            from_bitwise_digits_le(&v, bits)
169        } else {
170            from_inexact_bitwise_digits_le(&v, bits)
171        }
172    } else {
173        from_radix_digits_be(buf, radix)
174    };
175
176    Some(res)
177}
178
179pub(super) fn from_radix_le(buf: &[u8], radix: u32) -> Option<BigUint> {
180    assert!(
181        2 <= radix && radix <= 256,
182        "The radix must be within 2...256"
183    );
184
185    if buf.is_empty() {
186        return Some(Zero::zero());
187    }
188
189    if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
190        return None;
191    }
192
193    let res = if radix.is_power_of_two() {
194        // Powers of two can use bitwise masks and shifting instead of multiplication
195        let bits = ilog2(radix);
196        if big_digit::BITS % bits == 0 {
197            from_bitwise_digits_le(buf, bits)
198        } else {
199            from_inexact_bitwise_digits_le(buf, bits)
200        }
201    } else {
202        let mut v = Vec::from(buf);
203        v.reverse();
204        from_radix_digits_be(&v, radix)
205    };
206
207    Some(res)
208}
209
210impl Num for BigUint {
211    type FromStrRadixErr = ParseBigIntError;
212
213    /// Creates and initializes a `BigUint`.
214    fn from_str_radix(s: &str, radix: u32) -> Result<BigUint, ParseBigIntError> {
215        assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
216        let mut s = s;
217        if s.starts_with('+') {
218            let tail = &s[1..];
219            if !tail.starts_with('+') {
220                s = tail
221            }
222        }
223
224        if s.is_empty() {
225            return Err(ParseBigIntError::empty());
226        }
227
228        if s.starts_with('_') {
229            // Must lead with a real digit!
230            return Err(ParseBigIntError::invalid());
231        }
232
233        // First normalize all characters to plain digit values
234        let mut v = Vec::with_capacity(s.len());
235        for b in s.bytes() {
236            let d = match b {
237                b'0'..=b'9' => b - b'0',
238                b'a'..=b'z' => b - b'a' + 10,
239                b'A'..=b'Z' => b - b'A' + 10,
240                b'_' => continue,
241                _ => core::u8::MAX,
242            };
243            if d < radix as u8 {
244                v.push(d);
245            } else {
246                return Err(ParseBigIntError::invalid());
247            }
248        }
249
250        let res = if radix.is_power_of_two() {
251            // Powers of two can use bitwise masks and shifting instead of multiplication
252            let bits = ilog2(radix);
253            v.reverse();
254            if big_digit::BITS % bits == 0 {
255                from_bitwise_digits_le(&v, bits)
256            } else {
257                from_inexact_bitwise_digits_le(&v, bits)
258            }
259        } else {
260            from_radix_digits_be(&v, radix)
261        };
262        Ok(res)
263    }
264}
265
266fn high_bits_to_u64(v: &BigUint) -> u64 {
267    match v.data.len() {
268        0 => 0,
269        1 => {
270            // XXX Conversion is useless if already 64-bit.
271            #[allow(clippy::useless_conversion)]
272            let v0 = u64::from(v.data[0]);
273            v0
274        }
275        _ => {
276            let mut bits = v.bits();
277            let mut ret = 0u64;
278            let mut ret_bits = 0;
279
280            for d in v.data.iter().rev() {
281                let digit_bits = (bits - 1) % u64::from(big_digit::BITS) + 1;
282                let bits_want = Ord::min(64 - ret_bits, digit_bits);
283
284                if bits_want != 64 {
285                    ret <<= bits_want;
286                }
287                // XXX Conversion is useless if already 64-bit.
288                #[allow(clippy::useless_conversion)]
289                let d0 = u64::from(*d) >> (digit_bits - bits_want);
290                ret |= d0;
291                ret_bits += bits_want;
292                bits -= bits_want;
293
294                if ret_bits == 64 {
295                    break;
296                }
297            }
298
299            ret
300        }
301    }
302}
303
304impl ToPrimitive for BigUint {
305    #[inline]
306    fn to_i64(&self) -> Option<i64> {
307        self.to_u64().as_ref().and_then(u64::to_i64)
308    }
309
310    #[inline]
311    fn to_i128(&self) -> Option<i128> {
312        self.to_u128().as_ref().and_then(u128::to_i128)
313    }
314
315    #[allow(clippy::useless_conversion)]
316    #[inline]
317    fn to_u64(&self) -> Option<u64> {
318        let mut ret: u64 = 0;
319        let mut bits = 0;
320
321        for i in self.data.iter() {
322            if bits >= 64 {
323                return None;
324            }
325
326            // XXX Conversion is useless if already 64-bit.
327            ret += u64::from(*i) << bits;
328            bits += big_digit::BITS;
329        }
330
331        Some(ret)
332    }
333
334    #[inline]
335    fn to_u128(&self) -> Option<u128> {
336        let mut ret: u128 = 0;
337        let mut bits = 0;
338
339        for i in self.data.iter() {
340            if bits >= 128 {
341                return None;
342            }
343
344            ret |= u128::from(*i) << bits;
345            bits += big_digit::BITS;
346        }
347
348        Some(ret)
349    }
350
351    #[inline]
352    fn to_f32(&self) -> Option<f32> {
353        let mantissa = high_bits_to_u64(self);
354        let exponent = self.bits() - u64::from(fls(mantissa));
355
356        if exponent > core::f32::MAX_EXP as u64 {
357            Some(core::f32::INFINITY)
358        } else {
359            Some((mantissa as f32) * 2.0f32.powi(exponent as i32))
360        }
361    }
362
363    #[inline]
364    fn to_f64(&self) -> Option<f64> {
365        let mantissa = high_bits_to_u64(self);
366        let exponent = self.bits() - u64::from(fls(mantissa));
367
368        if exponent > core::f64::MAX_EXP as u64 {
369            Some(core::f64::INFINITY)
370        } else {
371            Some((mantissa as f64) * 2.0f64.powi(exponent as i32))
372        }
373    }
374}
375
376macro_rules! impl_try_from_biguint {
377    ($T:ty, $to_ty:path) => {
378        #[cfg(has_try_from)]
379        impl TryFrom<&BigUint> for $T {
380            type Error = TryFromBigIntError<()>;
381
382            #[inline]
383            fn try_from(value: &BigUint) -> Result<$T, TryFromBigIntError<()>> {
384                $to_ty(value).ok_or(TryFromBigIntError::new(()))
385            }
386        }
387
388        #[cfg(has_try_from)]
389        impl TryFrom<BigUint> for $T {
390            type Error = TryFromBigIntError<BigUint>;
391
392            #[inline]
393            fn try_from(value: BigUint) -> Result<$T, TryFromBigIntError<BigUint>> {
394                <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
395            }
396        }
397    };
398}
399
400impl_try_from_biguint!(u8, ToPrimitive::to_u8);
401impl_try_from_biguint!(u16, ToPrimitive::to_u16);
402impl_try_from_biguint!(u32, ToPrimitive::to_u32);
403impl_try_from_biguint!(u64, ToPrimitive::to_u64);
404impl_try_from_biguint!(usize, ToPrimitive::to_usize);
405impl_try_from_biguint!(u128, ToPrimitive::to_u128);
406
407impl_try_from_biguint!(i8, ToPrimitive::to_i8);
408impl_try_from_biguint!(i16, ToPrimitive::to_i16);
409impl_try_from_biguint!(i32, ToPrimitive::to_i32);
410impl_try_from_biguint!(i64, ToPrimitive::to_i64);
411impl_try_from_biguint!(isize, ToPrimitive::to_isize);
412impl_try_from_biguint!(i128, ToPrimitive::to_i128);
413
414impl FromPrimitive for BigUint {
415    #[inline]
416    fn from_i64(n: i64) -> Option<BigUint> {
417        if n >= 0 {
418            Some(BigUint::from(n as u64))
419        } else {
420            None
421        }
422    }
423
424    #[inline]
425    fn from_i128(n: i128) -> Option<BigUint> {
426        if n >= 0 {
427            Some(BigUint::from(n as u128))
428        } else {
429            None
430        }
431    }
432
433    #[inline]
434    fn from_u64(n: u64) -> Option<BigUint> {
435        Some(BigUint::from(n))
436    }
437
438    #[inline]
439    fn from_u128(n: u128) -> Option<BigUint> {
440        Some(BigUint::from(n))
441    }
442
443    #[inline]
444    fn from_f64(mut n: f64) -> Option<BigUint> {
445        // handle NAN, INFINITY, NEG_INFINITY
446        if !n.is_finite() {
447            return None;
448        }
449
450        // match the rounding of casting from float to int
451        n = n.trunc();
452
453        // handle 0.x, -0.x
454        if n.is_zero() {
455            return Some(BigUint::zero());
456        }
457
458        let (mantissa, exponent, sign) = FloatCore::integer_decode(n);
459
460        if sign == -1 {
461            return None;
462        }
463
464        let mut ret = BigUint::from(mantissa);
465        match exponent.cmp(&0) {
466            Greater => ret <<= exponent as usize,
467            Equal => {}
468            Less => ret >>= (-exponent) as usize,
469        }
470        Some(ret)
471    }
472}
473
474impl From<u64> for BigUint {
475    #[inline]
476    fn from(mut n: u64) -> Self {
477        let mut ret: BigUint = Zero::zero();
478
479        while n != 0 {
480            ret.data.push(n as BigDigit);
481            // don't overflow if BITS is 64:
482            n = (n >> 1) >> (big_digit::BITS - 1);
483        }
484
485        ret
486    }
487}
488
489impl From<u128> for BigUint {
490    #[inline]
491    fn from(mut n: u128) -> Self {
492        let mut ret: BigUint = Zero::zero();
493
494        while n != 0 {
495            ret.data.push(n as BigDigit);
496            n >>= big_digit::BITS;
497        }
498
499        ret
500    }
501}
502
503macro_rules! impl_biguint_from_uint {
504    ($T:ty) => {
505        impl From<$T> for BigUint {
506            #[inline]
507            fn from(n: $T) -> Self {
508                BigUint::from(n as u64)
509            }
510        }
511    };
512}
513
514impl_biguint_from_uint!(u8);
515impl_biguint_from_uint!(u16);
516impl_biguint_from_uint!(u32);
517impl_biguint_from_uint!(usize);
518
519macro_rules! impl_biguint_try_from_int {
520    ($T:ty, $from_ty:path) => {
521        #[cfg(has_try_from)]
522        impl TryFrom<$T> for BigUint {
523            type Error = TryFromBigIntError<()>;
524
525            #[inline]
526            fn try_from(value: $T) -> Result<BigUint, TryFromBigIntError<()>> {
527                $from_ty(value).ok_or(TryFromBigIntError::new(()))
528            }
529        }
530    };
531}
532
533impl_biguint_try_from_int!(i8, FromPrimitive::from_i8);
534impl_biguint_try_from_int!(i16, FromPrimitive::from_i16);
535impl_biguint_try_from_int!(i32, FromPrimitive::from_i32);
536impl_biguint_try_from_int!(i64, FromPrimitive::from_i64);
537impl_biguint_try_from_int!(isize, FromPrimitive::from_isize);
538impl_biguint_try_from_int!(i128, FromPrimitive::from_i128);
539
540impl ToBigUint for BigUint {
541    #[inline]
542    fn to_biguint(&self) -> Option<BigUint> {
543        Some(self.clone())
544    }
545}
546
547macro_rules! impl_to_biguint {
548    ($T:ty, $from_ty:path) => {
549        impl ToBigUint for $T {
550            #[inline]
551            fn to_biguint(&self) -> Option<BigUint> {
552                $from_ty(*self)
553            }
554        }
555    };
556}
557
558impl_to_biguint!(isize, FromPrimitive::from_isize);
559impl_to_biguint!(i8, FromPrimitive::from_i8);
560impl_to_biguint!(i16, FromPrimitive::from_i16);
561impl_to_biguint!(i32, FromPrimitive::from_i32);
562impl_to_biguint!(i64, FromPrimitive::from_i64);
563impl_to_biguint!(i128, FromPrimitive::from_i128);
564
565impl_to_biguint!(usize, FromPrimitive::from_usize);
566impl_to_biguint!(u8, FromPrimitive::from_u8);
567impl_to_biguint!(u16, FromPrimitive::from_u16);
568impl_to_biguint!(u32, FromPrimitive::from_u32);
569impl_to_biguint!(u64, FromPrimitive::from_u64);
570impl_to_biguint!(u128, FromPrimitive::from_u128);
571
572impl_to_biguint!(f32, FromPrimitive::from_f32);
573impl_to_biguint!(f64, FromPrimitive::from_f64);
574
575// Extract bitwise digits that evenly divide BigDigit
576pub(super) fn to_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
577    debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits == 0);
578
579    let last_i = u.data.len() - 1;
580    let mask: BigDigit = (1 << bits) - 1;
581    let digits_per_big_digit = big_digit::BITS / bits;
582    let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
583        .to_usize()
584        .unwrap_or(core::usize::MAX);
585    let mut res = Vec::with_capacity(digits);
586
587    for mut r in u.data[..last_i].iter().cloned() {
588        for _ in 0..digits_per_big_digit {
589            res.push((r & mask) as u8);
590            r >>= bits;
591        }
592    }
593
594    let mut r = u.data[last_i];
595    while r != 0 {
596        res.push((r & mask) as u8);
597        r >>= bits;
598    }
599
600    res
601}
602
603// Extract bitwise digits that don't evenly divide BigDigit
604fn to_inexact_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
605    debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits != 0);
606
607    let mask: BigDigit = (1 << bits) - 1;
608    let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
609        .to_usize()
610        .unwrap_or(core::usize::MAX);
611    let mut res = Vec::with_capacity(digits);
612
613    let mut r = 0;
614    let mut rbits = 0;
615
616    for c in &u.data {
617        r |= *c << rbits;
618        rbits += big_digit::BITS;
619
620        while rbits >= bits {
621            res.push((r & mask) as u8);
622            r >>= bits;
623
624            // r had more bits than it could fit - grab the bits we lost
625            if rbits > big_digit::BITS {
626                r = *c >> (big_digit::BITS - (rbits - bits));
627            }
628
629            rbits -= bits;
630        }
631    }
632
633    if rbits != 0 {
634        res.push(r as u8);
635    }
636
637    while let Some(&0) = res.last() {
638        res.pop();
639    }
640
641    res
642}
643
644// Extract little-endian radix digits
645#[inline(always)] // forced inline to get const-prop for radix=10
646pub(super) fn to_radix_digits_le(u: &BigUint, radix: u32) -> Vec<u8> {
647    debug_assert!(!u.is_zero() && !radix.is_power_of_two());
648
649    #[cfg(feature = "std")]
650    let radix_log2 = f64::from(radix).log2();
651    #[cfg(not(feature = "std"))]
652    let radix_log2 = ilog2(radix) as f64;
653
654    // Estimate how big the result will be, so we can pre-allocate it.
655    let radix_digits = ((u.bits() as f64) / radix_log2).ceil();
656    let mut res = Vec::with_capacity(radix_digits.to_usize().unwrap_or(0));
657
658    let mut digits = u.clone();
659
660    let (base, power) = get_radix_base(radix, big_digit::HALF_BITS);
661    let radix = radix as BigDigit;
662
663    // For very large numbers, the O(n²) loop of repeated `div_rem_digit` dominates the
664    // performance. We can mitigate this by dividing into chunks of a larger base first.
665    // The threshold for this was chosen by anecdotal performance measurements to
666    // approximate where this starts to make a noticeable difference.
667    if digits.data.len() >= 64 {
668        let mut big_base = BigUint::from(base * base);
669        let mut big_power = 2usize;
670
671        // Choose a target base length near √n.
672        let target_len = digits.data.len().sqrt();
673        while big_base.data.len() < target_len {
674            big_base = &big_base * &big_base;
675            big_power *= 2;
676        }
677
678        // This outer loop will run approximately √n times.
679        while digits > big_base {
680            // This is still the dominating factor, with n digits divided by √n digits.
681            let (q, mut big_r) = digits.div_rem(&big_base);
682            digits = q;
683
684            // This inner loop now has O(√n²)=O(n) behavior altogether.
685            for _ in 0..big_power {
686                let (q, mut r) = div_rem_digit(big_r, base);
687                big_r = q;
688                for _ in 0..power {
689                    res.push((r % radix) as u8);
690                    r /= radix;
691                }
692            }
693        }
694    }
695
696    while digits.data.len() > 1 {
697        let (q, mut r) = div_rem_digit(digits, base);
698        for _ in 0..power {
699            res.push((r % radix) as u8);
700            r /= radix;
701        }
702        digits = q;
703    }
704
705    let mut r = digits.data[0];
706    while r != 0 {
707        res.push((r % radix) as u8);
708        r /= radix;
709    }
710
711    res
712}
713
714pub(super) fn to_radix_le(u: &BigUint, radix: u32) -> Vec<u8> {
715    if u.is_zero() {
716        vec![0]
717    } else if radix.is_power_of_two() {
718        // Powers of two can use bitwise masks and shifting instead of division
719        let bits = ilog2(radix);
720        if big_digit::BITS % bits == 0 {
721            to_bitwise_digits_le(u, bits)
722        } else {
723            to_inexact_bitwise_digits_le(u, bits)
724        }
725    } else if radix == 10 {
726        // 10 is so common that it's worth separating out for const-propagation.
727        // Optimizers can often turn constant division into a faster multiplication.
728        to_radix_digits_le(u, 10)
729    } else {
730        to_radix_digits_le(u, radix)
731    }
732}
733
734pub(crate) fn to_str_radix_reversed(u: &BigUint, radix: u32) -> Vec<u8> {
735    assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
736
737    if u.is_zero() {
738        return vec![b'0'];
739    }
740
741    let mut res = to_radix_le(u, radix);
742
743    // Now convert everything to ASCII digits.
744    for r in &mut res {
745        debug_assert!(u32::from(*r) < radix);
746        if *r < 10 {
747            *r += b'0';
748        } else {
749            *r += b'a' - 10;
750        }
751    }
752    res
753}
754
755/// Returns the greatest power of the radix for the given bit size
756#[inline]
757fn get_radix_base(radix: u32, bits: u8) -> (BigDigit, usize) {
758    mod gen {
759        include! { concat!(env!("OUT_DIR"), "/radix_bases.rs") }
760    }
761
762    debug_assert!(
763        2 <= radix && radix <= 256,
764        "The radix must be within 2...256"
765    );
766    debug_assert!(!radix.is_power_of_two());
767    debug_assert!(bits <= big_digit::BITS);
768
769    match bits {
770        16 => {
771            let (base, power) = gen::BASES_16[radix as usize];
772            (base as BigDigit, power)
773        }
774        32 => {
775            let (base, power) = gen::BASES_32[radix as usize];
776            (base as BigDigit, power)
777        }
778        64 => {
779            let (base, power) = gen::BASES_64[radix as usize];
780            (base as BigDigit, power)
781        }
782        _ => panic!("Invalid bigdigit size"),
783    }
784}