// This uses stdlib features higher than the MSRV #![allow(clippy::manual_range_contains)] // 1.35 use super::{biguint_from_vec, BigUint, ToBigUint}; use super::addition::add2; use super::division::div_rem_digit; use super::multiplication::mac_with_carry; use crate::big_digit::{self, BigDigit}; use crate::std_alloc::Vec; use crate::ParseBigIntError; #[cfg(has_try_from)] use crate::TryFromBigIntError; use core::cmp::Ordering::{Equal, Greater, Less}; #[cfg(has_try_from)] use core::convert::TryFrom; use core::mem; use core::str::FromStr; use num_integer::{Integer, Roots}; use num_traits::float::FloatCore; use num_traits::{FromPrimitive, Num, One, PrimInt, ToPrimitive, Zero}; /// Find last set bit /// fls(0) == 0, fls(u32::MAX) == 32 fn fls(v: T) -> u8 { mem::size_of::() as u8 * 8 - v.leading_zeros() as u8 } fn ilog2(v: T) -> u8 { fls(v) - 1 } impl FromStr for BigUint { type Err = ParseBigIntError; #[inline] fn from_str(s: &str) -> Result { BigUint::from_str_radix(s, 10) } } // Convert from a power of two radix (bits == ilog2(radix)) where bits evenly divides // BigDigit::BITS pub(super) fn from_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint { debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits == 0); debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits))); let digits_per_big_digit = big_digit::BITS / bits; let data = v .chunks(digits_per_big_digit.into()) .map(|chunk| { chunk .iter() .rev() .fold(0, |acc, &c| (acc << bits) | BigDigit::from(c)) }) .collect(); biguint_from_vec(data) } // Convert from a power of two radix (bits == ilog2(radix)) where bits doesn't evenly divide // BigDigit::BITS fn from_inexact_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint { debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits != 0); debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits))); let total_bits = (v.len() as u64).saturating_mul(bits.into()); let big_digits = Integer::div_ceil(&total_bits, &big_digit::BITS.into()) .to_usize() .unwrap_or(core::usize::MAX); let mut data = Vec::with_capacity(big_digits); let mut d = 0; let mut dbits = 0; // number of bits we currently have in d // walk v accumululating bits in d; whenever we accumulate big_digit::BITS in d, spit out a // big_digit: for &c in v { d |= BigDigit::from(c) << dbits; dbits += bits; if dbits >= big_digit::BITS { data.push(d); dbits -= big_digit::BITS; // if dbits was > big_digit::BITS, we dropped some of the bits in c (they couldn't fit // in d) - grab the bits we lost here: d = BigDigit::from(c) >> (bits - dbits); } } if dbits > 0 { debug_assert!(dbits < big_digit::BITS); data.push(d as BigDigit); } biguint_from_vec(data) } // Read little-endian radix digits fn from_radix_digits_be(v: &[u8], radix: u32) -> BigUint { debug_assert!(!v.is_empty() && !radix.is_power_of_two()); debug_assert!(v.iter().all(|&c| u32::from(c) < radix)); // Estimate how big the result will be, so we can pre-allocate it. #[cfg(feature = "std")] let big_digits = { let radix_log2 = f64::from(radix).log2(); let bits = radix_log2 * v.len() as f64; (bits / big_digit::BITS as f64).ceil() }; #[cfg(not(feature = "std"))] let big_digits = { let radix_log2 = ilog2(radix.next_power_of_two()) as usize; let bits = radix_log2 * v.len(); (bits / big_digit::BITS as usize) + 1 }; let mut data = Vec::with_capacity(big_digits.to_usize().unwrap_or(0)); let (base, power) = get_radix_base(radix, big_digit::BITS); let radix = radix as BigDigit; let r = v.len() % power; let i = if r == 0 { power } else { r }; let (head, tail) = v.split_at(i); let first = head .iter() .fold(0, |acc, &d| acc * radix + BigDigit::from(d)); data.push(first); debug_assert!(tail.len() % power == 0); for chunk in tail.chunks(power) { if data.last() != Some(&0) { data.push(0); } let mut carry = 0; for d in data.iter_mut() { *d = mac_with_carry(0, *d, base, &mut carry); } debug_assert!(carry == 0); let n = chunk .iter() .fold(0, |acc, &d| acc * radix + BigDigit::from(d)); add2(&mut data, &[n]); } biguint_from_vec(data) } pub(super) fn from_radix_be(buf: &[u8], radix: u32) -> Option { assert!( 2 <= radix && radix <= 256, "The radix must be within 2...256" ); if buf.is_empty() { return Some(Zero::zero()); } if radix != 256 && buf.iter().any(|&b| b >= radix as u8) { return None; } let res = if radix.is_power_of_two() { // Powers of two can use bitwise masks and shifting instead of multiplication let bits = ilog2(radix); let mut v = Vec::from(buf); v.reverse(); if big_digit::BITS % bits == 0 { from_bitwise_digits_le(&v, bits) } else { from_inexact_bitwise_digits_le(&v, bits) } } else { from_radix_digits_be(buf, radix) }; Some(res) } pub(super) fn from_radix_le(buf: &[u8], radix: u32) -> Option { assert!( 2 <= radix && radix <= 256, "The radix must be within 2...256" ); if buf.is_empty() { return Some(Zero::zero()); } if radix != 256 && buf.iter().any(|&b| b >= radix as u8) { return None; } let res = if radix.is_power_of_two() { // Powers of two can use bitwise masks and shifting instead of multiplication let bits = ilog2(radix); if big_digit::BITS % bits == 0 { from_bitwise_digits_le(buf, bits) } else { from_inexact_bitwise_digits_le(buf, bits) } } else { let mut v = Vec::from(buf); v.reverse(); from_radix_digits_be(&v, radix) }; Some(res) } impl Num for BigUint { type FromStrRadixErr = ParseBigIntError; /// Creates and initializes a `BigUint`. fn from_str_radix(s: &str, radix: u32) -> Result { assert!(2 <= radix && radix <= 36, "The radix must be within 2...36"); let mut s = s; if s.starts_with('+') { let tail = &s[1..]; if !tail.starts_with('+') { s = tail } } if s.is_empty() { return Err(ParseBigIntError::empty()); } if s.starts_with('_') { // Must lead with a real digit! return Err(ParseBigIntError::invalid()); } // First normalize all characters to plain digit values let mut v = Vec::with_capacity(s.len()); for b in s.bytes() { let d = match b { b'0'..=b'9' => b - b'0', b'a'..=b'z' => b - b'a' + 10, b'A'..=b'Z' => b - b'A' + 10, b'_' => continue, _ => core::u8::MAX, }; if d < radix as u8 { v.push(d); } else { return Err(ParseBigIntError::invalid()); } } let res = if radix.is_power_of_two() { // Powers of two can use bitwise masks and shifting instead of multiplication let bits = ilog2(radix); v.reverse(); if big_digit::BITS % bits == 0 { from_bitwise_digits_le(&v, bits) } else { from_inexact_bitwise_digits_le(&v, bits) } } else { from_radix_digits_be(&v, radix) }; Ok(res) } } fn high_bits_to_u64(v: &BigUint) -> u64 { match v.data.len() { 0 => 0, 1 => { // XXX Conversion is useless if already 64-bit. #[allow(clippy::useless_conversion)] let v0 = u64::from(v.data[0]); v0 } _ => { let mut bits = v.bits(); let mut ret = 0u64; let mut ret_bits = 0; for d in v.data.iter().rev() { let digit_bits = (bits - 1) % u64::from(big_digit::BITS) + 1; let bits_want = Ord::min(64 - ret_bits, digit_bits); if bits_want != 0 { if bits_want != 64 { ret <<= bits_want; } // XXX Conversion is useless if already 64-bit. #[allow(clippy::useless_conversion)] let d0 = u64::from(*d) >> (digit_bits - bits_want); ret |= d0; } // Implement round-to-odd: If any lower bits are 1, set LSB to 1 // so that rounding again to floating point value using // nearest-ties-to-even is correct. // // See: https://en.wikipedia.org/wiki/Rounding#Rounding_to_prepare_for_shorter_precision if digit_bits - bits_want != 0 { // XXX Conversion is useless if already 64-bit. #[allow(clippy::useless_conversion)] let masked = u64::from(*d) << (64 - (digit_bits - bits_want) as u32); ret |= (masked != 0) as u64; } ret_bits += bits_want; bits -= bits_want; } ret } } } impl ToPrimitive for BigUint { #[inline] fn to_i64(&self) -> Option { self.to_u64().as_ref().and_then(u64::to_i64) } #[inline] fn to_i128(&self) -> Option { self.to_u128().as_ref().and_then(u128::to_i128) } #[allow(clippy::useless_conversion)] #[inline] fn to_u64(&self) -> Option { let mut ret: u64 = 0; let mut bits = 0; for i in self.data.iter() { if bits >= 64 { return None; } // XXX Conversion is useless if already 64-bit. ret += u64::from(*i) << bits; bits += big_digit::BITS; } Some(ret) } #[inline] fn to_u128(&self) -> Option { let mut ret: u128 = 0; let mut bits = 0; for i in self.data.iter() { if bits >= 128 { return None; } ret |= u128::from(*i) << bits; bits += big_digit::BITS; } Some(ret) } #[inline] fn to_f32(&self) -> Option { let mantissa = high_bits_to_u64(self); let exponent = self.bits() - u64::from(fls(mantissa)); if exponent > core::f32::MAX_EXP as u64 { Some(core::f32::INFINITY) } else { Some((mantissa as f32) * 2.0f32.powi(exponent as i32)) } } #[inline] fn to_f64(&self) -> Option { let mantissa = high_bits_to_u64(self); let exponent = self.bits() - u64::from(fls(mantissa)); if exponent > core::f64::MAX_EXP as u64 { Some(core::f64::INFINITY) } else { Some((mantissa as f64) * 2.0f64.powi(exponent as i32)) } } } macro_rules! impl_try_from_biguint { ($T:ty, $to_ty:path) => { #[cfg(has_try_from)] impl TryFrom<&BigUint> for $T { type Error = TryFromBigIntError<()>; #[inline] fn try_from(value: &BigUint) -> Result<$T, TryFromBigIntError<()>> { $to_ty(value).ok_or(TryFromBigIntError::new(())) } } #[cfg(has_try_from)] impl TryFrom for $T { type Error = TryFromBigIntError; #[inline] fn try_from(value: BigUint) -> Result<$T, TryFromBigIntError> { <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value)) } } }; } impl_try_from_biguint!(u8, ToPrimitive::to_u8); impl_try_from_biguint!(u16, ToPrimitive::to_u16); impl_try_from_biguint!(u32, ToPrimitive::to_u32); impl_try_from_biguint!(u64, ToPrimitive::to_u64); impl_try_from_biguint!(usize, ToPrimitive::to_usize); impl_try_from_biguint!(u128, ToPrimitive::to_u128); impl_try_from_biguint!(i8, ToPrimitive::to_i8); impl_try_from_biguint!(i16, ToPrimitive::to_i16); impl_try_from_biguint!(i32, ToPrimitive::to_i32); impl_try_from_biguint!(i64, ToPrimitive::to_i64); impl_try_from_biguint!(isize, ToPrimitive::to_isize); impl_try_from_biguint!(i128, ToPrimitive::to_i128); impl FromPrimitive for BigUint { #[inline] fn from_i64(n: i64) -> Option { if n >= 0 { Some(BigUint::from(n as u64)) } else { None } } #[inline] fn from_i128(n: i128) -> Option { if n >= 0 { Some(BigUint::from(n as u128)) } else { None } } #[inline] fn from_u64(n: u64) -> Option { Some(BigUint::from(n)) } #[inline] fn from_u128(n: u128) -> Option { Some(BigUint::from(n)) } #[inline] fn from_f64(mut n: f64) -> Option { // handle NAN, INFINITY, NEG_INFINITY if !n.is_finite() { return None; } // match the rounding of casting from float to int n = n.trunc(); // handle 0.x, -0.x if n.is_zero() { return Some(BigUint::zero()); } let (mantissa, exponent, sign) = FloatCore::integer_decode(n); if sign == -1 { return None; } let mut ret = BigUint::from(mantissa); match exponent.cmp(&0) { Greater => ret <<= exponent as usize, Equal => {} Less => ret >>= (-exponent) as usize, } Some(ret) } } impl From for BigUint { #[inline] fn from(mut n: u64) -> Self { let mut ret: BigUint = Zero::zero(); while n != 0 { ret.data.push(n as BigDigit); // don't overflow if BITS is 64: n = (n >> 1) >> (big_digit::BITS - 1); } ret } } impl From for BigUint { #[inline] fn from(mut n: u128) -> Self { let mut ret: BigUint = Zero::zero(); while n != 0 { ret.data.push(n as BigDigit); n >>= big_digit::BITS; } ret } } macro_rules! impl_biguint_from_uint { ($T:ty) => { impl From<$T> for BigUint { #[inline] fn from(n: $T) -> Self { BigUint::from(n as u64) } } }; } impl_biguint_from_uint!(u8); impl_biguint_from_uint!(u16); impl_biguint_from_uint!(u32); impl_biguint_from_uint!(usize); macro_rules! impl_biguint_try_from_int { ($T:ty, $from_ty:path) => { #[cfg(has_try_from)] impl TryFrom<$T> for BigUint { type Error = TryFromBigIntError<()>; #[inline] fn try_from(value: $T) -> Result> { $from_ty(value).ok_or(TryFromBigIntError::new(())) } } }; } impl_biguint_try_from_int!(i8, FromPrimitive::from_i8); impl_biguint_try_from_int!(i16, FromPrimitive::from_i16); impl_biguint_try_from_int!(i32, FromPrimitive::from_i32); impl_biguint_try_from_int!(i64, FromPrimitive::from_i64); impl_biguint_try_from_int!(isize, FromPrimitive::from_isize); impl_biguint_try_from_int!(i128, FromPrimitive::from_i128); impl ToBigUint for BigUint { #[inline] fn to_biguint(&self) -> Option { Some(self.clone()) } } macro_rules! impl_to_biguint { ($T:ty, $from_ty:path) => { impl ToBigUint for $T { #[inline] fn to_biguint(&self) -> Option { $from_ty(*self) } } }; } impl_to_biguint!(isize, FromPrimitive::from_isize); impl_to_biguint!(i8, FromPrimitive::from_i8); impl_to_biguint!(i16, FromPrimitive::from_i16); impl_to_biguint!(i32, FromPrimitive::from_i32); impl_to_biguint!(i64, FromPrimitive::from_i64); impl_to_biguint!(i128, FromPrimitive::from_i128); impl_to_biguint!(usize, FromPrimitive::from_usize); impl_to_biguint!(u8, FromPrimitive::from_u8); impl_to_biguint!(u16, FromPrimitive::from_u16); impl_to_biguint!(u32, FromPrimitive::from_u32); impl_to_biguint!(u64, FromPrimitive::from_u64); impl_to_biguint!(u128, FromPrimitive::from_u128); impl_to_biguint!(f32, FromPrimitive::from_f32); impl_to_biguint!(f64, FromPrimitive::from_f64); impl From for BigUint { fn from(x: bool) -> Self { if x { One::one() } else { Zero::zero() } } } // Extract bitwise digits that evenly divide BigDigit pub(super) fn to_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec { debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits == 0); let last_i = u.data.len() - 1; let mask: BigDigit = (1 << bits) - 1; let digits_per_big_digit = big_digit::BITS / bits; let digits = Integer::div_ceil(&u.bits(), &u64::from(bits)) .to_usize() .unwrap_or(core::usize::MAX); let mut res = Vec::with_capacity(digits); for mut r in u.data[..last_i].iter().cloned() { for _ in 0..digits_per_big_digit { res.push((r & mask) as u8); r >>= bits; } } let mut r = u.data[last_i]; while r != 0 { res.push((r & mask) as u8); r >>= bits; } res } // Extract bitwise digits that don't evenly divide BigDigit fn to_inexact_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec { debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits != 0); let mask: BigDigit = (1 << bits) - 1; let digits = Integer::div_ceil(&u.bits(), &u64::from(bits)) .to_usize() .unwrap_or(core::usize::MAX); let mut res = Vec::with_capacity(digits); let mut r = 0; let mut rbits = 0; for c in &u.data { r |= *c << rbits; rbits += big_digit::BITS; while rbits >= bits { res.push((r & mask) as u8); r >>= bits; // r had more bits than it could fit - grab the bits we lost if rbits > big_digit::BITS { r = *c >> (big_digit::BITS - (rbits - bits)); } rbits -= bits; } } if rbits != 0 { res.push(r as u8); } while let Some(&0) = res.last() { res.pop(); } res } // Extract little-endian radix digits #[inline(always)] // forced inline to get const-prop for radix=10 pub(super) fn to_radix_digits_le(u: &BigUint, radix: u32) -> Vec { debug_assert!(!u.is_zero() && !radix.is_power_of_two()); #[cfg(feature = "std")] let radix_digits = { let radix_log2 = f64::from(radix).log2(); ((u.bits() as f64) / radix_log2).ceil() }; #[cfg(not(feature = "std"))] let radix_digits = { let radix_log2 = ilog2(radix) as usize; ((u.bits() as usize) / radix_log2) + 1 }; // Estimate how big the result will be, so we can pre-allocate it. let mut res = Vec::with_capacity(radix_digits.to_usize().unwrap_or(0)); let mut digits = u.clone(); let (base, power) = get_radix_base(radix, big_digit::HALF_BITS); let radix = radix as BigDigit; // For very large numbers, the O(n²) loop of repeated `div_rem_digit` dominates the // performance. We can mitigate this by dividing into chunks of a larger base first. // The threshold for this was chosen by anecdotal performance measurements to // approximate where this starts to make a noticeable difference. if digits.data.len() >= 64 { let mut big_base = BigUint::from(base * base); let mut big_power = 2usize; // Choose a target base length near √n. let target_len = digits.data.len().sqrt(); while big_base.data.len() < target_len { big_base = &big_base * &big_base; big_power *= 2; } // This outer loop will run approximately √n times. while digits > big_base { // This is still the dominating factor, with n digits divided by √n digits. let (q, mut big_r) = digits.div_rem(&big_base); digits = q; // This inner loop now has O(√n²)=O(n) behavior altogether. for _ in 0..big_power { let (q, mut r) = div_rem_digit(big_r, base); big_r = q; for _ in 0..power { res.push((r % radix) as u8); r /= radix; } } } } while digits.data.len() > 1 { let (q, mut r) = div_rem_digit(digits, base); for _ in 0..power { res.push((r % radix) as u8); r /= radix; } digits = q; } let mut r = digits.data[0]; while r != 0 { res.push((r % radix) as u8); r /= radix; } res } pub(super) fn to_radix_le(u: &BigUint, radix: u32) -> Vec { if u.is_zero() { vec![0] } else if radix.is_power_of_two() { // Powers of two can use bitwise masks and shifting instead of division let bits = ilog2(radix); if big_digit::BITS % bits == 0 { to_bitwise_digits_le(u, bits) } else { to_inexact_bitwise_digits_le(u, bits) } } else if radix == 10 { // 10 is so common that it's worth separating out for const-propagation. // Optimizers can often turn constant division into a faster multiplication. to_radix_digits_le(u, 10) } else { to_radix_digits_le(u, radix) } } pub(crate) fn to_str_radix_reversed(u: &BigUint, radix: u32) -> Vec { assert!(2 <= radix && radix <= 36, "The radix must be within 2...36"); if u.is_zero() { return vec![b'0']; } let mut res = to_radix_le(u, radix); // Now convert everything to ASCII digits. for r in &mut res { debug_assert!(u32::from(*r) < radix); if *r < 10 { *r += b'0'; } else { *r += b'a' - 10; } } res } /// Returns the greatest power of the radix for the given bit size #[inline] fn get_radix_base(radix: u32, bits: u8) -> (BigDigit, usize) { mod gen { include! { concat!(env!("OUT_DIR"), "/radix_bases.rs") } } debug_assert!( 2 <= radix && radix <= 256, "The radix must be within 2...256" ); debug_assert!(!radix.is_power_of_two()); debug_assert!(bits <= big_digit::BITS); match bits { 16 => { let (base, power) = gen::BASES_16[radix as usize]; (base as BigDigit, power) } 32 => { let (base, power) = gen::BASES_32[radix as usize]; (base as BigDigit, power) } 64 => { let (base, power) = gen::BASES_64[radix as usize]; (base as BigDigit, power) } _ => panic!("Invalid bigdigit size"), } }