Skip to content

Commit 4685924

Browse files
authored
Merge pull request #599 from dhardy/merge-0.5
Merge 0.5
2 parents 9a4e62a + 00ff7fe commit 4685924

File tree

10 files changed

+169
-86
lines changed

10 files changed

+169
-86
lines changed

benches/seq.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<
116116
}
117117

118118
#[bench]
119-
fn seq_iter_unhinted_choose_from_100(b: &mut Bencher) {
119+
fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) {
120120
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
121121
let x : &[usize] = &[1; 1000];
122122
b.iter(|| {
@@ -125,9 +125,9 @@ fn seq_iter_unhinted_choose_from_100(b: &mut Bencher) {
125125
}
126126

127127
#[bench]
128-
fn seq_iter_window_hinted_choose_from_100(b: &mut Bencher) {
128+
fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) {
129129
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
130-
let x : &[usize] = &[1; 100];
130+
let x : &[usize] = &[1; 1000];
131131
b.iter(|| {
132132
WindowHintedIterator { iter: x.iter(), window_size: 7 }.choose(&mut rng)
133133
})

rand_core/src/block.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
285285
Self::new(R::from_seed(seed))
286286
}
287287

288+
fn seed_from_u64(seed: u64) -> Self {
289+
Self::new(R::seed_from_u64(seed))
290+
}
291+
288292
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
289293
Ok(Self::new(R::from_rng(rng)?))
290294
}
@@ -492,6 +496,10 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
492496
Self::new(R::from_seed(seed))
493497
}
494498

499+
fn seed_from_u64(seed: u64) -> Self {
500+
Self::new(R::seed_from_u64(seed))
501+
}
502+
495503
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
496504
Ok(Self::new(R::from_rng(rng)?))
497505
}

rand_core/src/lib.rs

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151

5252
use core::default::Default;
5353
use core::convert::AsMut;
54+
use core::ptr::copy_nonoverlapping;
5455

5556
#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box;
5657

@@ -296,7 +297,46 @@ pub trait SeedableRng: Sized {
296297
/// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad
297298
/// seed"). This is assuming only a small number of values must be rejected.
298299
fn from_seed(seed: Self::Seed) -> Self;
299-
300+
301+
/// Create a new PRNG using a `u64` seed.
302+
///
303+
/// This is a convenience-wrapper around `from_seed` to allow construction
304+
/// of any `SeedableRng` from a simple `u64` value. It is designed such that
305+
/// low Hamming Weight numbers like 0 and 1 can be used and should still
306+
/// result in good, independent seeds to the PRNG which is returned.
307+
///
308+
/// This **is not suitable for cryptography**, as should be clear given that
309+
/// the input size is only 64 bits.
310+
///
311+
/// Implementations for PRNGs *may* provide their own implementations of
312+
/// this function, but the default implementation should be good enough for
313+
/// all purposes. *Changing* the implementation of this function should be
314+
/// considered a value-breaking change.
315+
fn seed_from_u64(mut state: u64) -> Self {
316+
// We use PCG32 to generate a u32 sequence, and copy to the seed
317+
const MUL: u64 = 6364136223846793005;
318+
const INC: u64 = 11634580027462260723;
319+
320+
let mut seed = Self::Seed::default();
321+
for chunk in seed.as_mut().chunks_mut(4) {
322+
// We advance the state first (to get away from the input value,
323+
// in case it has low Hamming Weight).
324+
state = state.wrapping_mul(MUL).wrapping_add(INC);
325+
326+
// Use PCG output function with to_le to generate x:
327+
let xorshifted = (((state >> 18) ^ state) >> 27) as u32;
328+
let rot = (state >> 59) as u32;
329+
let x = xorshifted.rotate_right(rot).to_le();
330+
331+
unsafe {
332+
let p = &x as *const u32 as *const u8;
333+
copy_nonoverlapping(p, chunk.as_mut_ptr(), chunk.len());
334+
}
335+
}
336+
337+
Self::from_seed(seed)
338+
}
339+
300340
/// Create a new PRNG seeded from another `Rng`.
301341
///
302342
/// This is the recommended way to initialize PRNGs with fresh entropy. The
@@ -401,3 +441,46 @@ impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
401441
// Implement `CryptoRng` for boxed references to an `CryptoRng`.
402442
#[cfg(feature="alloc")]
403443
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
444+
445+
#[cfg(test)]
446+
mod test {
447+
use super::*;
448+
449+
#[test]
450+
fn test_seed_from_u64() {
451+
struct SeedableNum(u64);
452+
impl SeedableRng for SeedableNum {
453+
type Seed = [u8; 8];
454+
fn from_seed(seed: Self::Seed) -> Self {
455+
let mut x = [0u64; 1];
456+
le::read_u64_into(&seed, &mut x);
457+
SeedableNum(x[0])
458+
}
459+
}
460+
461+
const N: usize = 8;
462+
const SEEDS: [u64; N] = [0u64, 1, 2, 3, 4, 8, 16, -1i64 as u64];
463+
let mut results = [0u64; N];
464+
for (i, seed) in SEEDS.iter().enumerate() {
465+
let SeedableNum(x) = SeedableNum::seed_from_u64(*seed);
466+
results[i] = x;
467+
}
468+
469+
for (i1, r1) in results.iter().enumerate() {
470+
let weight = r1.count_ones();
471+
// This is the binomial distribution B(64, 0.5), so chance of
472+
// weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for
473+
// weight > 44.
474+
assert!(weight >= 20 && weight <= 44);
475+
476+
for (i2, r2) in results.iter().enumerate() {
477+
if i1 == i2 { continue; }
478+
let diff_weight = (r1 ^ r2).count_ones();
479+
assert!(diff_weight >= 20);
480+
}
481+
}
482+
483+
// value-breakage test:
484+
assert_eq!(results[0], 5029875928683246316);
485+
}
486+
}

rand_isaac/src/isaac.rs

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ impl SeedableRng for IsaacRng {
119119
fn from_seed(seed: Self::Seed) -> Self {
120120
IsaacRng(BlockRng::<IsaacCore>::from_seed(seed))
121121
}
122+
123+
/// Create an ISAAC random number generator using an `u64` as seed.
124+
/// If `seed == 0` this will produce the same stream of random numbers as
125+
/// the reference implementation when used unseeded.
126+
fn seed_from_u64(seed: u64) -> Self {
127+
IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed))
128+
}
122129

123130
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
124131
BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng))
@@ -129,8 +136,9 @@ impl IsaacRng {
129136
/// Create an ISAAC random number generator using an `u64` as seed.
130137
/// If `seed == 0` this will produce the same stream of random numbers as
131138
/// the reference implementation when used unseeded.
139+
#[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
132140
pub fn new_from_u64(seed: u64) -> Self {
133-
IsaacRng(BlockRng::new(IsaacCore::new_from_u64(seed)))
141+
Self::seed_from_u64(seed)
134142
}
135143
}
136144

@@ -301,22 +309,6 @@ impl IsaacCore {
301309

302310
Self { mem, a: w(0), b: w(0), c: w(0) }
303311
}
304-
305-
/// Create an ISAAC random number generator using an `u64` as seed.
306-
/// If `seed == 0` this will produce the same stream of random numbers as
307-
/// the reference implementation when used unseeded.
308-
fn new_from_u64(seed: u64) -> Self {
309-
let mut key = [w(0); RAND_SIZE];
310-
key[0] = w(seed as u32);
311-
key[1] = w((seed >> 32) as u32);
312-
// Initialize with only one pass.
313-
// A second pass does not improve the quality here, because all of the
314-
// seed was already available in the first round.
315-
// Not doing the second pass has the small advantage that if
316-
// `seed == 0` this method produces exactly the same state as the
317-
// reference implementation when used unseeded.
318-
Self::init(key, 1)
319-
}
320312
}
321313

322314
impl SeedableRng for IsaacCore {
@@ -332,6 +324,22 @@ impl SeedableRng for IsaacCore {
332324
}
333325
Self::init(seed_extended, 2)
334326
}
327+
328+
/// Create an ISAAC random number generator using an `u64` as seed.
329+
/// If `seed == 0` this will produce the same stream of random numbers as
330+
/// the reference implementation when used unseeded.
331+
fn seed_from_u64(seed: u64) -> Self {
332+
let mut key = [w(0); RAND_SIZE];
333+
key[0] = w(seed as u32);
334+
key[1] = w((seed >> 32) as u32);
335+
// Initialize with only one pass.
336+
// A second pass does not improve the quality here, because all of the
337+
// seed was already available in the first round.
338+
// Not doing the second pass has the small advantage that if
339+
// `seed == 0` this method produces exactly the same state as the
340+
// reference implementation when used unseeded.
341+
Self::init(key, 1)
342+
}
335343

336344
fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
337345
// Custom `from_rng` implementation that fills a seed with the same size
@@ -425,11 +433,11 @@ mod test {
425433
#[test]
426434
fn test_isaac_new_uninitialized() {
427435
// Compare the results from initializing `IsaacRng` with
428-
// `new_from_u64(0)`, to make sure it is the same as the reference
436+
// `seed_from_u64(0)`, to make sure it is the same as the reference
429437
// implementation when used uninitialized.
430438
// Note: We only test the first 16 integers, not the full 256 of the
431439
// first block.
432-
let mut rng = IsaacRng::new_from_u64(0);
440+
let mut rng = IsaacRng::seed_from_u64(0);
433441
let mut results = [0u32; 16];
434442
for i in results.iter_mut() { *i = rng.next_u32(); }
435443
let expected: [u32; 16] = [

rand_isaac/src/isaac64.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ impl SeedableRng for Isaac64Rng {
110110
Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed))
111111
}
112112

113+
/// Create an ISAAC random number generator using an `u64` as seed.
114+
/// If `seed == 0` this will produce the same stream of random numbers as
115+
/// the reference implementation when used unseeded.
116+
fn seed_from_u64(seed: u64) -> Self {
117+
Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed))
118+
}
119+
113120
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
114121
BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng))
115122
}
@@ -119,8 +126,9 @@ impl Isaac64Rng {
119126
/// Create an ISAAC-64 random number generator using an `u64` as seed.
120127
/// If `seed == 0` this will produce the same stream of random numbers as
121128
/// the reference implementation when used unseeded.
129+
#[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
122130
pub fn new_from_u64(seed: u64) -> Self {
123-
Isaac64Rng(BlockRng64::new(Isaac64Core::new_from_u64(seed)))
131+
Self::seed_from_u64(seed)
124132
}
125133
}
126134

@@ -270,16 +278,9 @@ impl Isaac64Core {
270278
/// Create an ISAAC-64 random number generator using an `u64` as seed.
271279
/// If `seed == 0` this will produce the same stream of random numbers as
272280
/// the reference implementation when used unseeded.
281+
#[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
273282
pub fn new_from_u64(seed: u64) -> Self {
274-
let mut key = [w(0); RAND_SIZE];
275-
key[0] = w(seed);
276-
// Initialize with only one pass.
277-
// A second pass does not improve the quality here, because all of the
278-
// seed was already available in the first round.
279-
// Not doing the second pass has the small advantage that if
280-
// `seed == 0` this method produces exactly the same state as the
281-
// reference implementation when used unseeded.
282-
Self::init(key, 1)
283+
Self::seed_from_u64(seed)
283284
}
284285
}
285286

@@ -296,6 +297,18 @@ impl SeedableRng for Isaac64Core {
296297
}
297298
Self::init(seed_extended, 2)
298299
}
300+
301+
fn seed_from_u64(seed: u64) -> Self {
302+
let mut key = [w(0); RAND_SIZE];
303+
key[0] = w(seed);
304+
// Initialize with only one pass.
305+
// A second pass does not improve the quality here, because all of the
306+
// seed was already available in the first round.
307+
// Not doing the second pass has the small advantage that if
308+
// `seed == 0` this method produces exactly the same state as the
309+
// reference implementation when used unseeded.
310+
Self::init(key, 1)
311+
}
299312

300313
fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
301314
// Custom `from_rng` implementation that fills a seed with the same size
@@ -415,11 +428,11 @@ mod test {
415428
#[test]
416429
fn test_isaac64_new_uninitialized() {
417430
// Compare the results from initializing `IsaacRng` with
418-
// `new_from_u64(0)`, to make sure it is the same as the reference
431+
// `seed_from_u64(0)`, to make sure it is the same as the reference
419432
// implementation when used uninitialized.
420433
// Note: We only test the first 16 integers, not the full 256 of the
421434
// first block.
422-
let mut rng = Isaac64Rng::new_from_u64(0);
435+
let mut rng = Isaac64Rng::seed_from_u64(0);
423436
let mut results = [0u64; 16];
424437
for i in results.iter_mut() { *i = rng.next_u64(); }
425438
let expected: [u64; 16] = [

src/distributions/unit_circle.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ mod tests {
9595
fn value_stability() {
9696
let mut rng = ::test::rng(2);
9797
let dist = UnitCircle::new();
98-
assert_eq!(dist.sample(&mut rng), [-0.8150602311723979, 0.5793762331690843]);
99-
assert_eq!(dist.sample(&mut rng), [-0.056204569973983196, 0.998419273809375]);
100-
assert_eq!(dist.sample(&mut rng), [0.7761923749562624, -0.630496151502733]);
98+
assert_eq!(dist.sample(&mut rng), [-0.8032118336637037, 0.5956935036263119]);
99+
assert_eq!(dist.sample(&mut rng), [-0.4742919588505423, -0.880367615130018]);
100+
assert_eq!(dist.sample(&mut rng), [0.9297328981467168, 0.368234623716601]);
101101
}
102102
}

src/distributions/unit_sphere.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ mod tests {
9191
let mut rng = ::test::rng(2);
9292
let dist = UnitSphereSurface::new();
9393
assert_eq!(dist.sample(&mut rng),
94-
[0.1660727273690104, 0.5202698793511903, 0.8376986939610902]);
94+
[-0.24950027180862533, -0.7552572587896719, 0.6060825747478084]);
9595
assert_eq!(dist.sample(&mut rng),
96-
[0.40052443371799834, 0.4237054996596154, -0.812436968356975]);
96+
[0.47604534507233487, -0.797200864987207, -0.3712837328763685]);
9797
assert_eq!(dist.sample(&mut rng),
98-
[0.9209910250970449, -0.32692477745072107, 0.21188610520628948]);
98+
[0.9795722330927367, 0.18692349236651176, 0.07414747571708524]);
9999
}
100100
}

src/lib.rs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -957,21 +957,7 @@ mod test {
957957
}
958958

959959
pub fn rng(seed: u64) -> TestRng<StdRng> {
960-
// TODO: use from_hashable
961-
let mut state = seed;
962-
let mut seed = <StdRng as SeedableRng>::Seed::default();
963-
for x in seed.iter_mut() {
964-
// PCG algorithm
965-
const MUL: u64 = 6364136223846793005;
966-
const INC: u64 = 11634580027462260723;
967-
let oldstate = state;
968-
state = oldstate.wrapping_mul(MUL).wrapping_add(INC);
969-
970-
let xorshifted = (((oldstate >> 18) ^ oldstate) >> 27) as u32;
971-
let rot = (oldstate >> 59) as u32;
972-
*x = xorshifted.rotate_right(rot) as u8;
973-
}
974-
TestRng { inner: StdRng::from_seed(seed) }
960+
TestRng { inner: StdRng::seed_from_u64(seed) }
975961
}
976962

977963
#[test]
@@ -1116,7 +1102,8 @@ mod test {
11161102
sum += 1;
11171103
}
11181104
}
1119-
let avg = (sum as f64) / (N as f64);
1120-
assert!((avg - (NUM as f64)/(DENOM as f64)).abs() < 1e-3);
1105+
// Have Binomial(N, NUM/DENOM) distribution
1106+
let expected = (NUM * N) / DENOM; // exact integer
1107+
assert!(((sum - expected) as i32).abs() < 500);
11211108
}
11221109
}

0 commit comments

Comments
 (0)