Skip to content

Commit ee2b80b

Browse files
bors[bot]cuviper
andauthored
Merge #143
143: Count big bits in u64 instead of usize r=cuviper a=cuviper A 32-bit target _could_ create a giant `BigUint` over 2²⁹ bytes = 512MB, not that this would be computationally useful, but that value would have more than `usize::MAX` bits. To avoid that possibility of overflow, we can better represent bit counts in `u64`. For 64-bit targets, a `BigUint` over 2⁶¹ bytes is not realistic. This changes the public API in the return values of `bits()` and `trailing_zeros()`, as well as the `bit_size` parameter of `RandBigInt` and `RandomBits`. Trying to randomize an absurd size will naturally cause a capacity overflow, just as if you'd made a huge `Vec`. Co-authored-by: Josh Stone <[email protected]>
2 parents 5b679e4 + 6d25cab commit ee2b80b

File tree

10 files changed

+86
-67
lines changed

10 files changed

+86
-67
lines changed

benches/bigint.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ fn get_rng() -> StdRng {
1818
SeedableRng::from_seed(seed)
1919
}
2020

21-
fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
21+
fn multiply_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
2222
let mut rng = get_rng();
2323
let x = rng.gen_bigint(xbits);
2424
let y = rng.gen_bigint(ybits);
2525

2626
b.iter(|| &x * &y);
2727
}
2828

29-
fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
29+
fn divide_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
3030
let mut rng = get_rng();
3131
let x = rng.gen_bigint(xbits);
3232
let y = rng.gen_bigint(ybits);
3333

3434
b.iter(|| &x / &y);
3535
}
3636

37-
fn remainder_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
37+
fn remainder_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
3838
let mut rng = get_rng();
3939
let x = rng.gen_bigint(xbits);
4040
let y = rng.gen_bigint(ybits);
@@ -245,7 +245,7 @@ fn from_str_radix_36(b: &mut Bencher) {
245245
from_str_radix_bench(b, 36);
246246
}
247247

248-
fn rand_bench(b: &mut Bencher, bits: usize) {
248+
fn rand_bench(b: &mut Bencher, bits: u64) {
249249
let mut rng = get_rng();
250250

251251
b.iter(|| rng.gen_bigint(bits));

benches/gcd.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn get_rng() -> StdRng {
1818
SeedableRng::from_seed(seed)
1919
}
2020

21-
fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) {
21+
fn bench(b: &mut Bencher, bits: u64, gcd: fn(&BigUint, &BigUint) -> BigUint) {
2222
let mut rng = get_rng();
2323
let x = rng.gen_biguint(bits);
2424
let y = rng.gen_biguint(bits);

benches/roots.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn check(x: &BigUint, n: u32) {
4343
assert_eq!((&hi - 1u32).nth_root(n), root);
4444
}
4545

46-
fn bench_sqrt(b: &mut Bencher, bits: usize) {
46+
fn bench_sqrt(b: &mut Bencher, bits: u64) {
4747
let x = get_rng().gen_biguint(bits);
4848
eprintln!("bench_sqrt({})", x);
4949

@@ -71,7 +71,7 @@ fn big4k_sqrt(b: &mut Bencher) {
7171
bench_sqrt(b, 4096);
7272
}
7373

74-
fn bench_cbrt(b: &mut Bencher, bits: usize) {
74+
fn bench_cbrt(b: &mut Bencher, bits: u64) {
7575
let x = get_rng().gen_biguint(bits);
7676
eprintln!("bench_cbrt({})", x);
7777

@@ -99,7 +99,7 @@ fn big4k_cbrt(b: &mut Bencher) {
9999
bench_cbrt(b, 4096);
100100
}
101101

102-
fn bench_nth_root(b: &mut Bencher, bits: usize, n: u32) {
102+
fn bench_nth_root(b: &mut Bencher, bits: u64, n: u32) {
103103
let x = get_rng().gen_biguint(bits);
104104
eprintln!("bench_{}th_root({})", n, x);
105105

ci/big_rand/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ mod biguint {
102102
let mut rng = R::from_seed(seed);
103103
for (i, &s) in expected.iter().enumerate() {
104104
let n: BigUint = s.parse().unwrap();
105-
let r = rng.gen_biguint((1 << i) + i);
105+
let r = rng.gen_biguint((1 << i) + i as u64);
106106
assert_eq!(n, r);
107107
}
108108
}
@@ -302,7 +302,7 @@ mod bigint {
302302
let mut rng = R::from_seed(seed);
303303
for (i, &s) in expected.iter().enumerate() {
304304
let n: BigInt = s.parse().unwrap();
305-
let r = rng.gen_bigint((1 << i) + i);
305+
let r = rng.gen_bigint((1 << i) + i as u64);
306306
assert_eq!(n, r);
307307
}
308308
}

src/algorithms.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
521521
// Recomposition. The coefficients of the polynomial are now known.
522522
//
523523
// Evaluate at w(t) where t is our given base to get the result.
524-
let bits = big_digit::BITS * i;
524+
let bits = u64::from(big_digit::BITS) * i as u64;
525525
let result = r0
526526
+ (comp1 << bits)
527527
+ (comp2 << (2 * bits))
@@ -720,11 +720,11 @@ fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) {
720720

721721
/// Find last set bit
722722
/// fls(0) == 0, fls(u32::MAX) == 32
723-
pub(crate) fn fls<T: PrimInt>(v: T) -> usize {
724-
mem::size_of::<T>() * 8 - v.leading_zeros() as usize
723+
pub(crate) fn fls<T: PrimInt>(v: T) -> u8 {
724+
mem::size_of::<T>() as u8 * 8 - v.leading_zeros() as u8
725725
}
726726

727-
pub(crate) fn ilog2<T: PrimInt>(v: T) -> usize {
727+
pub(crate) fn ilog2<T: PrimInt>(v: T) -> u8 {
728728
fls(v) - 1
729729
}
730730

src/bigint.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,7 @@ impl_shift! { i8, i16, i32, i64, i128, isize }
875875
fn shr_round_down<T: PrimInt>(i: &BigInt, shift: T) -> bool {
876876
if i.is_negative() {
877877
let zeros = i.trailing_zeros().expect("negative values are non-zero");
878-
shift > T::zero() && shift.to_usize().map(|shift| zeros < shift).unwrap_or(true)
878+
shift > T::zero() && shift.to_u64().map(|shift| zeros < shift).unwrap_or(true)
879879
} else {
880880
false
881881
}
@@ -3195,7 +3195,7 @@ impl BigInt {
31953195
/// Determines the fewest bits necessary to express the `BigInt`,
31963196
/// not including the sign.
31973197
#[inline]
3198-
pub fn bits(&self) -> usize {
3198+
pub fn bits(&self) -> u64 {
31993199
self.data.bits()
32003200
}
32013201

@@ -3290,7 +3290,7 @@ impl BigInt {
32903290

32913291
/// Returns the number of least-significant bits that are zero,
32923292
/// or `None` if the entire number is zero.
3293-
pub fn trailing_zeros(&self) -> Option<usize> {
3293+
pub fn trailing_zeros(&self) -> Option<u64> {
32943294
self.data.trailing_zeros()
32953295
}
32963296
}

src/bigrand.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ use crate::bigint::{into_magnitude, magnitude};
1111
use crate::biguint::biguint_from_vec;
1212

1313
use num_integer::Integer;
14-
use num_traits::Zero;
14+
use num_traits::{ToPrimitive, Zero};
1515

1616
/// A trait for sampling random big integers.
1717
///
1818
/// The `rand` feature must be enabled to use this. See crate-level documentation for details.
1919
pub trait RandBigInt {
2020
/// Generate a random `BigUint` of the given bit size.
21-
fn gen_biguint(&mut self, bit_size: usize) -> BigUint;
21+
fn gen_biguint(&mut self, bit_size: u64) -> BigUint;
2222

2323
/// Generate a random BigInt of the given bit size.
24-
fn gen_bigint(&mut self, bit_size: usize) -> BigInt;
24+
fn gen_bigint(&mut self, bit_size: u64) -> BigInt;
2525

2626
/// Generate a random `BigUint` less than the given bound. Fails
2727
/// when the bound is zero.
@@ -38,7 +38,7 @@ pub trait RandBigInt {
3838
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
3939
}
4040

41-
fn gen_bits<R: Rng + ?Sized>(rng: &mut R, data: &mut [u32], rem: usize) {
41+
fn gen_bits<R: Rng + ?Sized>(rng: &mut R, data: &mut [u32], rem: u64) {
4242
// `fill` is faster than many `gen::<u32>` calls
4343
rng.fill(data);
4444
if rem > 0 {
@@ -49,25 +49,31 @@ fn gen_bits<R: Rng + ?Sized>(rng: &mut R, data: &mut [u32], rem: usize) {
4949

5050
impl<R: Rng + ?Sized> RandBigInt for R {
5151
#[cfg(not(u64_digit))]
52-
fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
52+
fn gen_biguint(&mut self, bit_size: u64) -> BigUint {
5353
let (digits, rem) = bit_size.div_rem(&32);
54-
let mut data = vec![0u32; digits + (rem > 0) as usize];
54+
let len = (digits + (rem > 0) as u64)
55+
.to_usize()
56+
.expect("capacity overflow");
57+
let mut data = vec![0u32; len];
5558
gen_bits(self, &mut data, rem);
5659
biguint_from_vec(data)
5760
}
5861

5962
#[cfg(u64_digit)]
60-
fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
63+
fn gen_biguint(&mut self, bit_size: u64) -> BigUint {
6164
use core::slice;
6265

6366
let (digits, rem) = bit_size.div_rem(&32);
67+
let len = (digits + (rem > 0) as u64)
68+
.to_usize()
69+
.expect("capacity overflow");
6470
let native_digits = bit_size.div_ceil(&64);
65-
let mut data = vec![0u64; native_digits];
71+
let native_len = native_digits.to_usize().expect("capacity overflow");
72+
let mut data = vec![0u64; native_len];
6673
unsafe {
6774
// Generate bits in a `&mut [u32]` slice for value stability
6875
let ptr = data.as_mut_ptr() as *mut u32;
69-
let len = digits + (rem > 0) as usize;
70-
debug_assert!(native_digits * 2 >= len);
76+
debug_assert!(native_len * 2 >= len);
7177
let data = slice::from_raw_parts_mut(ptr, len);
7278
gen_bits(self, data, rem);
7379
}
@@ -79,7 +85,7 @@ impl<R: Rng + ?Sized> RandBigInt for R {
7985
biguint_from_vec(data)
8086
}
8187

82-
fn gen_bigint(&mut self, bit_size: usize) -> BigInt {
88+
fn gen_bigint(&mut self, bit_size: u64) -> BigInt {
8389
loop {
8490
// Generate a random BigUint...
8591
let biguint = self.gen_biguint(bit_size);
@@ -253,12 +259,12 @@ impl SampleUniform for BigInt {
253259
/// The `rand` feature must be enabled to use this. See crate-level documentation for details.
254260
#[derive(Clone, Copy, Debug)]
255261
pub struct RandomBits {
256-
bits: usize,
262+
bits: u64,
257263
}
258264

259265
impl RandomBits {
260266
#[inline]
261-
pub fn new(bits: usize) -> RandomBits {
267+
pub fn new(bits: u64) -> RandomBits {
262268
RandomBits { bits }
263269
}
264270
}

0 commit comments

Comments
 (0)