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