diff --git a/benches/bigint.rs b/benches/bigint.rs index e1ec45e5..591e9a99 100644 --- a/benches/bigint.rs +++ b/benches/bigint.rs @@ -18,7 +18,7 @@ fn get_rng() -> StdRng { SeedableRng::from_seed(seed) } -fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) { +fn multiply_bench(b: &mut Bencher, xbits: u64, ybits: u64) { let mut rng = get_rng(); let x = rng.gen_bigint(xbits); let y = rng.gen_bigint(ybits); @@ -26,7 +26,7 @@ fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) { b.iter(|| &x * &y); } -fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) { +fn divide_bench(b: &mut Bencher, xbits: u64, ybits: u64) { let mut rng = get_rng(); let x = rng.gen_bigint(xbits); let y = rng.gen_bigint(ybits); @@ -34,7 +34,7 @@ fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) { b.iter(|| &x / &y); } -fn remainder_bench(b: &mut Bencher, xbits: usize, ybits: usize) { +fn remainder_bench(b: &mut Bencher, xbits: u64, ybits: u64) { let mut rng = get_rng(); let x = rng.gen_bigint(xbits); let y = rng.gen_bigint(ybits); @@ -245,7 +245,7 @@ fn from_str_radix_36(b: &mut Bencher) { from_str_radix_bench(b, 36); } -fn rand_bench(b: &mut Bencher, bits: usize) { +fn rand_bench(b: &mut Bencher, bits: u64) { let mut rng = get_rng(); b.iter(|| rng.gen_bigint(bits)); diff --git a/benches/gcd.rs b/benches/gcd.rs index e6c54b5a..1a65654c 100644 --- a/benches/gcd.rs +++ b/benches/gcd.rs @@ -18,7 +18,7 @@ fn get_rng() -> StdRng { SeedableRng::from_seed(seed) } -fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) { +fn bench(b: &mut Bencher, bits: u64, gcd: fn(&BigUint, &BigUint) -> BigUint) { let mut rng = get_rng(); let x = rng.gen_biguint(bits); let y = rng.gen_biguint(bits); diff --git a/benches/roots.rs b/benches/roots.rs index e6113136..2433cf0a 100644 --- a/benches/roots.rs +++ b/benches/roots.rs @@ -43,7 +43,7 @@ fn check(x: &BigUint, n: u32) { assert_eq!((&hi - 1u32).nth_root(n), root); } -fn bench_sqrt(b: &mut Bencher, bits: usize) { +fn bench_sqrt(b: &mut Bencher, bits: u64) { let x = get_rng().gen_biguint(bits); eprintln!("bench_sqrt({})", x); @@ -71,7 +71,7 @@ fn big4k_sqrt(b: &mut Bencher) { bench_sqrt(b, 4096); } -fn bench_cbrt(b: &mut Bencher, bits: usize) { +fn bench_cbrt(b: &mut Bencher, bits: u64) { let x = get_rng().gen_biguint(bits); eprintln!("bench_cbrt({})", x); @@ -99,7 +99,7 @@ fn big4k_cbrt(b: &mut Bencher) { bench_cbrt(b, 4096); } -fn bench_nth_root(b: &mut Bencher, bits: usize, n: u32) { +fn bench_nth_root(b: &mut Bencher, bits: u64, n: u32) { let x = get_rng().gen_biguint(bits); eprintln!("bench_{}th_root({})", n, x); diff --git a/ci/big_rand/src/lib.rs b/ci/big_rand/src/lib.rs index 2c22db0a..1bea5750 100644 --- a/ci/big_rand/src/lib.rs +++ b/ci/big_rand/src/lib.rs @@ -102,7 +102,7 @@ mod biguint { let mut rng = R::from_seed(seed); for (i, &s) in expected.iter().enumerate() { let n: BigUint = s.parse().unwrap(); - let r = rng.gen_biguint((1 << i) + i); + let r = rng.gen_biguint((1 << i) + i as u64); assert_eq!(n, r); } } @@ -302,7 +302,7 @@ mod bigint { let mut rng = R::from_seed(seed); for (i, &s) in expected.iter().enumerate() { let n: BigInt = s.parse().unwrap(); - let r = rng.gen_bigint((1 << i) + i); + let r = rng.gen_bigint((1 << i) + i as u64); assert_eq!(n, r); } } diff --git a/src/algorithms.rs b/src/algorithms.rs index d6a5625a..7952f939 100644 --- a/src/algorithms.rs +++ b/src/algorithms.rs @@ -521,7 +521,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) { // Recomposition. The coefficients of the polynomial are now known. // // Evaluate at w(t) where t is our given base to get the result. - let bits = big_digit::BITS * i; + let bits = u64::from(big_digit::BITS) * i as u64; let result = r0 + (comp1 << bits) + (comp2 << (2 * bits)) @@ -720,11 +720,11 @@ fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) { /// Find last set bit /// fls(0) == 0, fls(u32::MAX) == 32 -pub(crate) fn fls(v: T) -> usize { - mem::size_of::() * 8 - v.leading_zeros() as usize +pub(crate) fn fls(v: T) -> u8 { + mem::size_of::() as u8 * 8 - v.leading_zeros() as u8 } -pub(crate) fn ilog2(v: T) -> usize { +pub(crate) fn ilog2(v: T) -> u8 { fls(v) - 1 } diff --git a/src/bigint.rs b/src/bigint.rs index 3a5d226f..1e20f503 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -875,7 +875,7 @@ impl_shift! { i8, i16, i32, i64, i128, isize } fn shr_round_down(i: &BigInt, shift: T) -> bool { if i.is_negative() { let zeros = i.trailing_zeros().expect("negative values are non-zero"); - shift > T::zero() && shift.to_usize().map(|shift| zeros < shift).unwrap_or(true) + shift > T::zero() && shift.to_u64().map(|shift| zeros < shift).unwrap_or(true) } else { false } @@ -3195,7 +3195,7 @@ impl BigInt { /// Determines the fewest bits necessary to express the `BigInt`, /// not including the sign. #[inline] - pub fn bits(&self) -> usize { + pub fn bits(&self) -> u64 { self.data.bits() } @@ -3290,7 +3290,7 @@ impl BigInt { /// Returns the number of least-significant bits that are zero, /// or `None` if the entire number is zero. - pub fn trailing_zeros(&self) -> Option { + pub fn trailing_zeros(&self) -> Option { self.data.trailing_zeros() } } diff --git a/src/bigrand.rs b/src/bigrand.rs index 864f75d7..ae00b7e4 100644 --- a/src/bigrand.rs +++ b/src/bigrand.rs @@ -11,17 +11,17 @@ use crate::bigint::{into_magnitude, magnitude}; use crate::biguint::biguint_from_vec; use num_integer::Integer; -use num_traits::Zero; +use num_traits::{ToPrimitive, Zero}; /// A trait for sampling random big integers. /// /// The `rand` feature must be enabled to use this. See crate-level documentation for details. pub trait RandBigInt { /// Generate a random `BigUint` of the given bit size. - fn gen_biguint(&mut self, bit_size: usize) -> BigUint; + fn gen_biguint(&mut self, bit_size: u64) -> BigUint; /// Generate a random BigInt of the given bit size. - fn gen_bigint(&mut self, bit_size: usize) -> BigInt; + fn gen_bigint(&mut self, bit_size: u64) -> BigInt; /// Generate a random `BigUint` less than the given bound. Fails /// when the bound is zero. @@ -38,7 +38,7 @@ pub trait RandBigInt { fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt; } -fn gen_bits(rng: &mut R, data: &mut [u32], rem: usize) { +fn gen_bits(rng: &mut R, data: &mut [u32], rem: u64) { // `fill` is faster than many `gen::` calls rng.fill(data); if rem > 0 { @@ -49,25 +49,31 @@ fn gen_bits(rng: &mut R, data: &mut [u32], rem: usize) { impl RandBigInt for R { #[cfg(not(u64_digit))] - fn gen_biguint(&mut self, bit_size: usize) -> BigUint { + fn gen_biguint(&mut self, bit_size: u64) -> BigUint { let (digits, rem) = bit_size.div_rem(&32); - let mut data = vec![0u32; digits + (rem > 0) as usize]; + let len = (digits + (rem > 0) as u64) + .to_usize() + .expect("capacity overflow"); + let mut data = vec![0u32; len]; gen_bits(self, &mut data, rem); biguint_from_vec(data) } #[cfg(u64_digit)] - fn gen_biguint(&mut self, bit_size: usize) -> BigUint { + fn gen_biguint(&mut self, bit_size: u64) -> BigUint { use core::slice; let (digits, rem) = bit_size.div_rem(&32); + let len = (digits + (rem > 0) as u64) + .to_usize() + .expect("capacity overflow"); let native_digits = bit_size.div_ceil(&64); - let mut data = vec![0u64; native_digits]; + let native_len = native_digits.to_usize().expect("capacity overflow"); + let mut data = vec![0u64; native_len]; unsafe { // Generate bits in a `&mut [u32]` slice for value stability let ptr = data.as_mut_ptr() as *mut u32; - let len = digits + (rem > 0) as usize; - debug_assert!(native_digits * 2 >= len); + debug_assert!(native_len * 2 >= len); let data = slice::from_raw_parts_mut(ptr, len); gen_bits(self, data, rem); } @@ -79,7 +85,7 @@ impl RandBigInt for R { biguint_from_vec(data) } - fn gen_bigint(&mut self, bit_size: usize) -> BigInt { + fn gen_bigint(&mut self, bit_size: u64) -> BigInt { loop { // Generate a random BigUint... let biguint = self.gen_biguint(bit_size); @@ -253,12 +259,12 @@ impl SampleUniform for BigInt { /// The `rand` feature must be enabled to use this. See crate-level documentation for details. #[derive(Clone, Copy, Debug)] pub struct RandomBits { - bits: usize, + bits: u64, } impl RandomBits { #[inline] - pub fn new(bits: usize) -> RandomBits { + pub fn new(bits: u64) -> RandomBits { RandomBits { bits } } } diff --git a/src/biguint.rs b/src/biguint.rs index 53684185..ff256e48 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -216,14 +216,14 @@ impl FromStr for BigUint { // Convert from a power of two radix (bits == ilog2(radix)) where bits evenly divides // BigDigit::BITS -fn from_bitwise_digits_le(v: &[u8], bits: usize) -> BigUint { +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) + .chunks(digits_per_big_digit.into()) .map(|chunk| { chunk .iter() @@ -237,11 +237,15 @@ fn from_bitwise_digits_le(v: &[u8], bits: usize) -> BigUint { // 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: usize) -> BigUint { +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 big_digits = (v.len() * bits + big_digit::BITS - 1) / big_digit::BITS; + let big_digits = (v.len() as u64) + .saturating_mul(bits.into()) + .div_ceil(&big_digit::BITS.into()) + .to_usize() + .unwrap_or(core::usize::MAX); let mut data = Vec::with_capacity(big_digits); let mut d = 0; @@ -1587,7 +1591,7 @@ impl Integer for BigUint { #[inline] fn gcd(&self, other: &Self) -> Self { #[inline] - fn twos(x: &BigUint) -> usize { + fn twos(x: &BigUint) -> u64 { x.trailing_zeros().unwrap_or(0) } @@ -1688,7 +1692,7 @@ impl Integer for BigUint { } #[inline] -fn fixpoint(mut x: BigUint, max_bits: usize, f: F) -> BigUint +fn fixpoint(mut x: BigUint, max_bits: u64, f: F) -> BigUint where F: Fn(&BigUint) -> BigUint, { @@ -1739,7 +1743,8 @@ impl Roots for BigUint { // The root of non-zero values less than 2ⁿ can only be 1. let bits = self.bits(); - if bits <= n as usize { + let n64 = u64::from(n); + if bits <= n64 { return BigUint::one(); } @@ -1748,7 +1753,7 @@ impl Roots for BigUint { return x.nth_root(n).into(); } - let max_bits = bits / n as usize + 1; + let max_bits = bits / n64 + 1; #[cfg(feature = "std")] let guess = if let Some(f) = self.to_f64() { @@ -1757,11 +1762,10 @@ impl Roots for BigUint { } else { // Try to guess by scaling down such that it does fit in `f64`. // With some (x * 2ⁿᵏ), its nth root ≈ (ⁿ√x * 2ᵏ) - let nsz = n as usize; - let extra_bits = bits - (f64::MAX_EXP as usize - 1); - let root_scale = (extra_bits + (nsz - 1)) / nsz; - let scale = root_scale * nsz; - if scale < bits && bits - scale > nsz { + let extra_bits = bits - (f64::MAX_EXP as u64 - 1); + let root_scale = extra_bits.div_ceil(&n64); + let scale = root_scale * n64; + if scale < bits && bits - scale > n64 { (self >> scale).nth_root(n) << root_scale } else { BigUint::one() << max_bits @@ -1792,7 +1796,7 @@ impl Roots for BigUint { } let bits = self.bits(); - let max_bits = bits / 2 as usize + 1; + let max_bits = bits / 2 + 1; #[cfg(feature = "std")] let guess = if let Some(f) = self.to_f64() { @@ -1801,7 +1805,7 @@ impl Roots for BigUint { } else { // Try to guess by scaling down such that it does fit in `f64`. // With some (x * 2²ᵏ), its sqrt ≈ (√x * 2ᵏ) - let extra_bits = bits - (f64::MAX_EXP as usize - 1); + let extra_bits = bits - (f64::MAX_EXP as u64 - 1); let root_scale = (extra_bits + 1) / 2; let scale = root_scale * 2; (self >> scale).sqrt() << root_scale @@ -1828,7 +1832,7 @@ impl Roots for BigUint { } let bits = self.bits(); - let max_bits = bits / 3 as usize + 1; + let max_bits = bits / 3 + 1; #[cfg(feature = "std")] let guess = if let Some(f) = self.to_f64() { @@ -1837,7 +1841,7 @@ impl Roots for BigUint { } else { // Try to guess by scaling down such that it does fit in `f64`. // With some (x * 2³ᵏ), its cbrt ≈ (∛x * 2ᵏ) - let extra_bits = bits - (f64::MAX_EXP as usize - 1); + let extra_bits = bits - (f64::MAX_EXP as u64 - 1); let root_scale = (extra_bits + 2) / 3; let scale = root_scale * 3; (self >> scale).cbrt() << root_scale @@ -1864,7 +1868,7 @@ fn high_bits_to_u64(v: &BigUint) -> u64 { let mut ret_bits = 0; for d in v.data.iter().rev() { - let digit_bits = (bits - 1) % big_digit::BITS + 1; + let digit_bits = (bits - 1) % u64::from(big_digit::BITS) + 1; let bits_want = cmp::min(64 - ret_bits, digit_bits); if bits_want != 64 { @@ -1932,9 +1936,9 @@ impl ToPrimitive for BigUint { #[inline] fn to_f32(&self) -> Option { let mantissa = high_bits_to_u64(self); - let exponent = self.bits() - fls(mantissa); + let exponent = self.bits() - u64::from(fls(mantissa)); - if exponent > f32::MAX_EXP as usize { + if exponent > f32::MAX_EXP as u64 { None } else { let ret = (mantissa as f32) * 2.0f32.powi(exponent as i32); @@ -1949,9 +1953,9 @@ impl ToPrimitive for BigUint { #[inline] fn to_f64(&self) -> Option { let mantissa = high_bits_to_u64(self); - let exponent = self.bits() - fls(mantissa); + let exponent = self.bits() - u64::from(fls(mantissa)); - if exponent > f64::MAX_EXP as usize { + if exponent > f64::MAX_EXP as u64 { None } else { let ret = (mantissa as f64) * 2.0f64.powi(exponent as i32); @@ -2170,13 +2174,17 @@ impl_to_biguint!(f32, FromPrimitive::from_f32); impl_to_biguint!(f64, FromPrimitive::from_f64); // Extract bitwise digits that evenly divide BigDigit -fn to_bitwise_digits_le(u: &BigUint, bits: usize) -> Vec { +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 = (u.bits() + bits - 1) / bits; + let digits = u + .bits() + .div_ceil(&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() { @@ -2196,11 +2204,15 @@ fn to_bitwise_digits_le(u: &BigUint, bits: usize) -> Vec { } // Extract bitwise digits that don't evenly divide BigDigit -fn to_inexact_bitwise_digits_le(u: &BigUint, bits: usize) -> Vec { +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 = (u.bits() + bits - 1) / bits; + let digits = u + .bits() + .div_ceil(&u64::from(bits)) + .to_usize() + .unwrap_or(core::usize::MAX); let mut res = Vec::with_capacity(digits); let mut r = 0; @@ -2659,12 +2671,12 @@ impl BigUint { /// Determines the fewest bits necessary to express the `BigUint`. #[inline] - pub fn bits(&self) -> usize { + pub fn bits(&self) -> u64 { if self.is_zero() { return 0; } - let zeros = self.data.last().unwrap().leading_zeros(); - self.data.len() * big_digit::BITS - zeros as usize + let zeros: u64 = self.data.last().unwrap().leading_zeros().into(); + self.data.len() as u64 * u64::from(big_digit::BITS) - zeros } /// Strips off trailing zero bigdigits - comparisons require the last element in the vector to @@ -2723,9 +2735,10 @@ impl BigUint { /// Returns the number of least-significant bits that are zero, /// or `None` if the entire number is zero. - pub fn trailing_zeros(&self) -> Option { + pub fn trailing_zeros(&self) -> Option { let i = self.data.iter().position(|&digit| digit != 0)?; - Some(i * big_digit::BITS + self.data[i].trailing_zeros() as usize) + let zeros: u64 = self.data[i].trailing_zeros().into(); + Some(i as u64 * u64::from(big_digit::BITS) + zeros) } } @@ -2745,7 +2758,7 @@ fn plain_modpow(base: &BigUint, exp_data: &[BigDigit], modulus: &BigUint) -> Big } let mut r = exp_data[i]; - let mut b = 0usize; + let mut b = 0u8; while r.is_even() { base = &base * &base % modulus; r >>= 1; @@ -2984,7 +2997,7 @@ impl<'de> serde::Deserialize<'de> for BigUint { /// Returns the greatest power of the radix for the given bit size #[inline] -fn get_radix_base(radix: u32, bits: usize) -> (BigDigit, usize) { +fn get_radix_base(radix: u32, bits: u8) -> (BigDigit, usize) { mod gen { include! { concat!(env!("OUT_DIR"), "/radix_bases.rs") } } diff --git a/src/lib.rs b/src/lib.rs index 7b757840..30c5abec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -258,11 +258,11 @@ mod big_digit { // `DoubleBigDigit` size dependent #[cfg(not(u64_digit))] - pub(crate) const BITS: usize = 32; + pub(crate) const BITS: u8 = 32; #[cfg(u64_digit)] - pub(crate) const BITS: usize = 64; + pub(crate) const BITS: u8 = 64; - pub(crate) const HALF_BITS: usize = BITS / 2; + pub(crate) const HALF_BITS: u8 = BITS / 2; pub(crate) const HALF: BigDigit = (1 << HALF_BITS) - 1; const LO_MASK: DoubleBigDigit = (1 << BITS) - 1; diff --git a/src/monty.rs b/src/monty.rs index 0307ec82..b9a0bd06 100644 --- a/src/monty.rs +++ b/src/monty.rs @@ -150,7 +150,7 @@ pub(crate) fn monty_modpow(x: &BigUint, y: &BigUint, m: &BigUint) -> BigUint { // rr = 2**(2*_W*len(m)) mod m let mut rr = BigUint::one(); - rr = (rr.shl(2 * num_words * big_digit::BITS)) % m; + rr = (rr.shl(2 * num_words as u64 * u64::from(big_digit::BITS))) % m; if rr.data.len() < num_words { rr.data.resize(num_words, 0); }