Skip to content

Generate random BigUints and BigInts #9007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/libextra/num/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use std::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
use std::int;
use std::num;
use std::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable};
use std::rand::{Rng, RngUtil};
use std::str;
use std::uint;
use std::vec;
Expand Down Expand Up @@ -1051,6 +1052,53 @@ impl FromStrRadix for BigInt {
}
}

trait RandBigInt {
/// Generate a random BigUint of the given bit size.
fn gen_biguint(&mut self, bit_size: uint) -> BigUint;

/// Generate a random BigInt of the given bit size.
fn gen_bigint(&mut self, bit_size: uint) -> BigInt;
}

impl<R: Rng> RandBigInt for R {
/// Generate a random BigUint of the given bit size.
fn gen_biguint(&mut self, bit_size: uint) -> BigUint {
let (digits, rem) = bit_size.div_rem(&BigDigit::bits);
let mut data = vec::with_capacity(digits+1);
for _ in range(0, digits) {
data.push(self.gen());
}
if rem > 0 {
let final_digit: BigDigit = self.gen();
data.push(final_digit >> (BigDigit::bits - rem));
}
return BigUint::new(data);
}

/// Generate a random BigInt of the given bit size.
fn gen_bigint(&mut self, bit_size: uint) -> BigInt {
// Generate a random BigUint...
let biguint = self.gen_biguint(bit_size);
// ...and then randomly assign it a Sign...
let sign = if biguint.is_zero() {
// ...except that if the BigUint is zero, we need to try
// again with probability 0.5. This is because otherwise,
// the probability of generating a zero BigInt would be
// double that of any other number.
if self.gen() {
return self.gen_bigint(bit_size);
} else {
Zero
}
} else if self.gen() {
Plus
} else {
Minus
};
return BigInt::from_biguint(sign, biguint);
}
}

impl BigInt {
/// Creates and initializes an BigInt.
#[inline]
Expand Down Expand Up @@ -1112,6 +1160,7 @@ mod biguint_tests {
use std::cmp::{Less, Equal, Greater};
use std::int;
use std::num::{IntConvertible, Zero, One, FromStrRadix};
use std::rand::{task_rng};
use std::str;
use std::uint;
use std::vec;
Expand Down Expand Up @@ -1577,6 +1626,13 @@ mod biguint_tests {
check(20, "2432902008176640000");
check(30, "265252859812191058636308480000000");
}

#[test]
fn test_rand() {
let mut rng = task_rng();
let _n: BigUint = rng.gen_biguint(137);
assert!(rng.gen_biguint(0).is_zero());
}
}

#[cfg(test)]
Expand All @@ -1586,6 +1642,7 @@ mod bigint_tests {
use std::cmp::{Less, Equal, Greater};
use std::int;
use std::num::{IntConvertible, Zero, One, FromStrRadix};
use std::rand::{task_rng};
use std::uint;

#[test]
Expand Down Expand Up @@ -2006,6 +2063,13 @@ mod bigint_tests {
let zero: BigInt = Zero::zero();
assert_eq!(-zero, zero);
}

#[test]
fn test_rand() {
let mut rng = task_rng();
let _n: BigInt = rng.gen_bigint(137);
assert!(rng.gen_bigint(0).is_zero());
}
}

#[cfg(test)]
Expand Down