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