impl SampleUniform for BigUint

This commit is contained in:
Josh Stone 2018-05-22 14:48:52 -07:00
parent 39104f5732
commit 4ef07c4625
3 changed files with 65 additions and 3 deletions

View File

@ -1,6 +1,7 @@
//! Randomization of big integers
use rand::Rng;
use rand::distributions::uniform::{SampleUniform, UniformSampler};
use BigInt;
use BigUint;
@ -34,8 +35,7 @@ pub trait RandBigInt {
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
}
#[cfg(any(feature = "rand", test))]
impl<R: Rng> RandBigInt for R {
impl<R: Rng + ?Sized> RandBigInt for R {
fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
use super::big_digit::BITS;
let (digits, rem) = bit_size.div_rem(&BITS);
@ -106,3 +106,40 @@ impl<R: Rng> RandBigInt for R {
}
}
}
/// The back-end implementing rand's `UniformSampler` for `BigUint`.
#[derive(Clone, Debug)]
pub struct UniformBigUint {
base: BigUint,
len: BigUint,
}
impl UniformSampler for UniformBigUint {
type X = BigUint;
fn new(low: Self::X, high: Self::X) -> Self {
assert!(low < high);
UniformBigUint {
len: high - &low,
base: low,
}
}
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
assert!(low <= high);
Self::new(low, high + 1u32)
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
&self.base + rng.gen_biguint_below(&self.len)
}
fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
rng.gen_biguint_range(&low, &high)
}
}
impl SampleUniform for BigUint {
type Sampler = UniformBigUint;
}

View File

@ -163,7 +163,7 @@ pub use bigint::BigInt;
pub use bigint::ToBigInt;
#[cfg(feature = "rand")]
pub use bigrand::RandBigInt;
pub use bigrand::{RandBigInt, UniformBigUint};
mod big_digit {
/// A `BigDigit` is a `BigUint`'s composing element.

View File

@ -8,6 +8,8 @@ mod biguint {
use num_bigint::{BigUint, RandBigInt};
use num_traits::Zero;
use rand::thread_rng;
use rand::Rng;
use rand::distributions::Uniform;
#[test]
fn test_rand() {
@ -54,6 +56,29 @@ mod biguint {
// Switching u and l should fail:
let _n: BigUint = rng.gen_biguint_range(&u, &l);
}
#[test]
fn test_rand_uniform() {
let mut rng = thread_rng();
let tiny = Uniform::new(BigUint::from(236u32), BigUint::from(237u32));
for _ in 0..10 {
assert_eq!(rng.sample(&tiny), BigUint::from(236u32));
}
let l = BigUint::from(403469000u32 + 2352);
let u = BigUint::from(403469000u32 + 3513);
let below = Uniform::new(BigUint::zero(), u.clone());
let range = Uniform::new(l.clone(), u.clone());
for _ in 0..1000 {
let n: BigUint = rng.sample(&below);
assert!(n < u);
let n: BigUint = rng.sample(&range);
assert!(n >= l);
assert!(n < u);
}
}
}
mod bigint {