impl SampleUniform for BigInt

This commit is contained in:
Josh Stone 2018-05-22 14:59:36 -07:00
parent 4ef07c4625
commit b72822bbde
4 changed files with 74 additions and 2 deletions

View File

@ -117,6 +117,14 @@ pub fn magnitude(i: &BigInt) -> &BigUint {
&i.data
}
/// Return the owned magnitude of a `BigInt`.
///
/// This is in a private module, pseudo pub(crate)
#[cfg(feature = "rand")]
pub fn into_magnitude(i: BigInt) -> BigUint {
i.data
}
impl PartialEq for BigInt {
#[inline]
fn eq(&self, other: &BigInt) -> bool {

View File

@ -8,7 +8,7 @@ use BigUint;
use Sign::*;
use big_digit::BigDigit;
use bigint::magnitude;
use bigint::{magnitude, into_magnitude};
use traits::Zero;
use integer::Integer;
@ -143,3 +143,40 @@ impl UniformSampler for UniformBigUint {
impl SampleUniform for BigUint {
type Sampler = UniformBigUint;
}
/// The back-end implementing rand's `UniformSampler` for `BigInt`.
#[derive(Clone, Debug)]
pub struct UniformBigInt {
base: BigInt,
len: BigUint,
}
impl UniformSampler for UniformBigInt {
type X = BigInt;
fn new(low: Self::X, high: Self::X) -> Self {
assert!(low < high);
UniformBigInt {
len: into_magnitude(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 + BigInt::from(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_bigint_range(&low, &high)
}
}
impl SampleUniform for BigInt {
type Sampler = UniformBigInt;
}

View File

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

View File

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