Skip to content
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

switch gen_biguint to fill_bytes #53

Merged
merged 3 commits into from
Jul 5, 2018
Merged
Show file tree
Hide file tree
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
46 changes: 46 additions & 0 deletions benches/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,52 @@ fn from_str_radix_36(b: &mut Bencher) {
from_str_radix_bench(b, 36);
}

fn rand_bench(b: &mut Bencher, bits: usize) {
let mut rng = get_rng();

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

#[bench]
fn rand_64(b: &mut Bencher) {
rand_bench(b, 1 << 6);
}

#[bench]
fn rand_256(b: &mut Bencher) {
rand_bench(b, 1 << 8);
}

#[bench]
fn rand_1009(b: &mut Bencher) {
rand_bench(b, 1009);
}

#[bench]
fn rand_2048(b: &mut Bencher) {
rand_bench(b, 1 << 11);
}

#[bench]
fn rand_4096(b: &mut Bencher) {
rand_bench(b, 1 << 12);
}

#[bench]
fn rand_8192(b: &mut Bencher) {
rand_bench(b, 1 << 13);
}

#[bench]
fn rand_65536(b: &mut Bencher) {
rand_bench(b, 1 << 16);
}

#[bench]
fn rand_131072(b: &mut Bencher) {
rand_bench(b, 1 << 17);
}

#[bench]
fn shl(b: &mut Bencher) {
let n = BigUint::one() << 1000;
Expand Down
15 changes: 9 additions & 6 deletions src/bigrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use rand::prelude::*;
use rand::distributions::uniform::{SampleUniform, UniformSampler};
use rand::AsByteSliceMut;

use BigInt;
use BigUint;
Expand Down Expand Up @@ -39,13 +40,15 @@ 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);
let mut data = Vec::with_capacity(digits + 1);
for _ in 0..digits {
data.push(self.gen());
}
let mut data = vec![BigDigit::default(); digits + (rem > 0) as usize];
// `fill_bytes` is faster than many `gen::<u32>` calls
self.fill_bytes(data[..].as_byte_slice_mut());
// Swap bytes per the `Rng::fill` source. This might be
// unnecessary if reproducibility across architectures is not
// desired.
data.to_le();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting question -- what guarantees should we make about reproducibility? Is this PR a breaking change altogether, since seeded RNGs may now produce a different BigUint? Maybe that's going too far to consider this across crate versions, but if we want it across architectures, we'll also need to be careful in the future about conditional BigDigit sizes, for instance. (Right now this is using the public BigUint::new though, which should always be u32-based even if the internals change.)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be a value-breaking change (depending on the PRNG used), but I think will usually not be. (Rand does not specify that fill_bytes must output the same bits in the same order as repeated calls to next_u32, though I think this is the case for all current generators.)

if rem > 0 {
let final_digit: BigDigit = self.gen();
data.push(final_digit >> (BITS - rem));
data[digits] >>= BITS - rem;
}
BigUint::new(data)
}
Expand Down
144 changes: 142 additions & 2 deletions tests/rand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod biguint {
use num_bigint::{BigUint, RandBigInt, RandomBits};
use num_traits::Zero;
use rand::thread_rng;
use rand::Rng;
use rand::{Rng, SeedableRng};
use rand::distributions::Uniform;

#[test]
Expand Down Expand Up @@ -89,13 +89,83 @@ mod biguint {
assert!(n < u);
}
}

fn seeded_value_stability<R: SeedableRng + RandBigInt>(expected: &[&str]) {
let mut seed = <R::Seed>::default();
for (i, x) in seed.as_mut().iter_mut().enumerate() {
*x = (i as u8).wrapping_mul(191);
}
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);
assert_eq!(n, r);
}
}

#[test]
fn test_chacha_value_stability() {
const EXPECTED: &[&str] = &[
"0",
"0",
"52",
"84",
"23780",
"86502865016",
"187057847319509867386",
"34045731223080904464438757488196244981910",
"23813754422987836414755953516143692594193066497413249270287126597896871975915808",
"57401636903146945411652549098818446911814352529449356393690984105383482703074355\
67088360974672291353736011718191813678720755501317478656550386324355699624671",
];
use rand::prng::ChaChaRng;
seeded_value_stability::<ChaChaRng>(EXPECTED);
}

#[test]
fn test_isaac_value_stability() {
const EXPECTED: &[&str] = &[
"1",
"4",
"3",
"649",
"89116",
"7730042024",
"20773149082453254949",
"35999009049239918667571895439206839620281",
"10191757312714088681302309313551624007714035309632506837271600807524767413673006",
"37805949268912387809989378008822038725134260145886913321084097194957861133272558\
43458183365174899239251448892645546322463253898288141861183340823194379722556",
];
use rand::prng::IsaacRng;
seeded_value_stability::<IsaacRng>(EXPECTED);
}

#[test]
fn test_xorshift_value_stability() {
const EXPECTED: &[&str] = &[
"1",
"0",
"37",
"395",
"181116",
"122718231117",
"1068467172329355695001",
"28246925743544411614293300167064395633287",
"12750053187017853048648861493745244146555950255549630854523304068318587267293038",
"53041498719137109355568081064978196049094604705283682101683207799515709404788873\
53417136457745727045473194367732849819278740266658219147356315674940229288531",
];
use rand::prng::XorShiftRng;
seeded_value_stability::<XorShiftRng>(EXPECTED);
}
}

mod bigint {
use num_bigint::{BigInt, RandBigInt, RandomBits};
use num_traits::Zero;
use rand::thread_rng;
use rand::Rng;
use rand::{Rng, SeedableRng};
use rand::distributions::Uniform;

#[test]
Expand Down Expand Up @@ -181,4 +251,74 @@ mod bigint {
check(-l.clone(), u.clone());
check(-u.clone(), -l.clone());
}

fn seeded_value_stability<R: SeedableRng + RandBigInt>(expected: &[&str]) {
let mut seed = <R::Seed>::default();
for (i, x) in seed.as_mut().iter_mut().enumerate() {
*x = (i as u8).wrapping_mul(191);
}
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);
assert_eq!(n, r);
}
}

#[test]
fn test_chacha_value_stability() {
const EXPECTED: &[&str] = &[
"0",
"-6",
"-1",
"1321",
"-147247",
"8486373526",
"-272736656290199720696",
"2731152629387534140535423510744221288522",
"-28820024790651190394679732038637785320661450462089347915910979466834461433196572",
"501454570554170484799723603981439288209930393334472085317977614690773821680884844\
8530978478667288338327570972869032358120588620346111979053742269317702532328",
];
use rand::prng::ChaChaRng;
seeded_value_stability::<ChaChaRng>(EXPECTED);
}

#[test]
fn test_isaac_value_stability() {
const EXPECTED: &[&str] = &[
"1",
"0",
"5",
"113",
"-132240",
"-36348760761",
"-365690596708430705434",
"-14090753008246284277803606722552430292432",
"-26313941628626248579319341019368550803676255307056857978955881718727601479436059",
"-14563174552421101848999036239003801073335703811160945137332228646111920972691151\
88341090358094331641182310792892459091016794928947242043358702692294695845817",
];
use rand::prng::IsaacRng;
seeded_value_stability::<IsaacRng>(EXPECTED);
}

#[test]
fn test_xorshift_value_stability() {
const EXPECTED: &[&str] = &[
"-1",
"-4",
"11",
"-1802",
"966495",
"-62592045703",
"-602281783447192077116",
"-34335811410223060575607987996861632509125",
"29156580925282215857325937227200350542000244609280383263289720243118706105351199",
"49920038676141573457451407325930326489996232208489690499754573826911037849083623\
24546142615325187412887314466195222441945661833644117700809693098722026764846",
];
use rand::prng::XorShiftRng;
seeded_value_stability::<XorShiftRng>(EXPECTED);
}
}