Skip to content

Commit 8a8cdcc

Browse files
committed
implement xorshift128+
1 parent e61752f commit 8a8cdcc

File tree

3 files changed

+268
-139
lines changed

3 files changed

+268
-139
lines changed

benches/bench.rs

Lines changed: 38 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,64 +3,52 @@
33
extern crate test;
44
extern crate rand;
55

6-
const RAND_BENCH_N: u64 = 100;
7-
86
mod distributions;
97

10-
use std::mem::size_of;
11-
use test::{black_box, Bencher};
12-
use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng};
13-
use rand::{OsRng, weak_rng};
8+
use test::Bencher;
9+
use rand::{weak_rng, Rng};
1410

15-
#[bench]
16-
fn rand_xorshift(b: &mut Bencher) {
17-
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
18-
b.iter(|| {
19-
for _ in 0..RAND_BENCH_N {
20-
black_box(rng.gen::<usize>());
21-
}
22-
});
23-
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
24-
}
25-
26-
#[bench]
27-
fn rand_isaac(b: &mut Bencher) {
28-
let mut rng: IsaacRng = OsRng::new().unwrap().gen();
29-
b.iter(|| {
30-
for _ in 0..RAND_BENCH_N {
31-
black_box(rng.gen::<usize>());
32-
}
33-
});
34-
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
35-
}
36-
37-
#[bench]
38-
fn rand_isaac64(b: &mut Bencher) {
39-
let mut rng: Isaac64Rng = OsRng::new().unwrap().gen();
40-
b.iter(|| {
41-
for _ in 0..RAND_BENCH_N {
42-
black_box(rng.gen::<usize>());
43-
}
44-
});
45-
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
46-
}
47-
48-
#[bench]
49-
fn rand_std(b: &mut Bencher) {
50-
let mut rng = StdRng::new().unwrap();
51-
b.iter(|| {
52-
for _ in 0..RAND_BENCH_N {
53-
black_box(rng.gen::<usize>());
54-
}
55-
});
56-
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
57-
}
11+
pub const RAND_BENCH_N: u64 = 100;
5812

5913
#[bench]
6014
fn rand_shuffle_100(b: &mut Bencher) {
6115
let mut rng = weak_rng();
6216
let x : &mut [usize] = &mut [1; 100];
6317
b.iter(|| {
64-
rng.shuffle(x);
18+
rng.shuffle(x)
6519
})
6620
}
21+
22+
mod algorithms {
23+
use test::{black_box, Bencher};
24+
use std::mem::size_of;
25+
use rand::{OsRng, XorShift64Rng, XorShift128PRng, IsaacRng, Isaac64Rng, Rng, ChaChaRng};
26+
27+
use super::*;
28+
29+
macro_rules! impl_bench {
30+
($result_ty: ty: $fn_name: ident, $hasher: ident) => (
31+
#[bench]
32+
fn $fn_name(b: &mut Bencher) {
33+
let mut rng: $hasher = OsRng::new().unwrap().gen();
34+
b.iter(|| {
35+
for _ in 0..RAND_BENCH_N {
36+
black_box(rng.gen::<$result_ty>());
37+
}
38+
});
39+
b.bytes = size_of::<$result_ty>() as u64 * RAND_BENCH_N;
40+
}
41+
)
42+
}
43+
44+
impl_bench!(u32: xorshift_u32, XorShift64Rng);
45+
impl_bench!(u64: xorshift_u64, XorShift64Rng);
46+
impl_bench!(u32: xorshiftp_u32, XorShift128PRng);
47+
impl_bench!(u64: xorshiftp_u64, XorShift128PRng);
48+
impl_bench!(u32: isaac_u32, IsaacRng);
49+
impl_bench!(u64: isaac_u64, IsaacRng);
50+
impl_bench!(u32: isaac64_u32, Isaac64Rng);
51+
impl_bench!(u64: isaac64_u64, Isaac64Rng);
52+
impl_bench!(u32: chacha_u32, ChaChaRng);
53+
impl_bench!(u64: chacha_u64, ChaChaRng);
54+
}

src/lib.rs

Lines changed: 28 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -254,18 +254,25 @@ pub use os::OsRng;
254254

255255
pub use isaac::{IsaacRng, Isaac64Rng};
256256
pub use chacha::ChaChaRng;
257+
pub use xorshift::{XorShift64Rng, XorShift128PRng};
257258

258259
#[cfg(target_pointer_width = "32")]
259260
use IsaacRng as IsaacWordRng;
260261
#[cfg(target_pointer_width = "64")]
261262
use Isaac64Rng as IsaacWordRng;
262263

264+
#[cfg(target_pointer_width = "32")]
265+
use XorShift64Rng as InnerWeakRng;
266+
#[cfg(target_pointer_width = "64")]
267+
use XorShift128PRng as InnerWeakRng;
268+
263269
use distributions::{Range, IndependentSample};
264270
use distributions::range::SampleRange;
265271

266272
pub mod distributions;
267273
pub mod isaac;
268274
pub mod chacha;
275+
pub mod xorshift;
269276
pub mod reseeding;
270277
mod rand_impls;
271278
pub mod os;
@@ -598,93 +605,6 @@ pub trait SeedableRng<Seed>: Rng {
598605
fn from_seed(seed: Seed) -> Self;
599606
}
600607

601-
/// An Xorshift[1] random number
602-
/// generator.
603-
///
604-
/// The Xorshift algorithm is not suitable for cryptographic purposes
605-
/// but is very fast. If you do not know for sure that it fits your
606-
/// requirements, use a more secure one such as `IsaacRng` or `OsRng`.
607-
///
608-
/// [1]: Marsaglia, George (July 2003). ["Xorshift
609-
/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of
610-
/// Statistical Software*. Vol. 8 (Issue 14).
611-
#[allow(missing_copy_implementations)]
612-
#[derive(Clone)]
613-
pub struct XorShiftRng {
614-
x: w32,
615-
y: w32,
616-
z: w32,
617-
w: w32,
618-
}
619-
620-
impl XorShiftRng {
621-
/// Creates a new XorShiftRng instance which is not seeded.
622-
///
623-
/// The initial values of this RNG are constants, so all generators created
624-
/// by this function will yield the same stream of random numbers. It is
625-
/// highly recommended that this is created through `SeedableRng` instead of
626-
/// this function
627-
pub fn new_unseeded() -> XorShiftRng {
628-
XorShiftRng {
629-
x: w(0x193a6754),
630-
y: w(0xa8a7d469),
631-
z: w(0x97830e05),
632-
w: w(0x113ba7bb),
633-
}
634-
}
635-
}
636-
637-
impl Rng for XorShiftRng {
638-
#[inline]
639-
fn next_u32(&mut self) -> u32 {
640-
let x = self.x;
641-
let t = x ^ (x << 11);
642-
self.x = self.y;
643-
self.y = self.z;
644-
self.z = self.w;
645-
let w_ = self.w;
646-
self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
647-
self.w.0
648-
}
649-
}
650-
651-
impl SeedableRng<[u32; 4]> for XorShiftRng {
652-
/// Reseed an XorShiftRng. This will panic if `seed` is entirely 0.
653-
fn reseed(&mut self, seed: [u32; 4]) {
654-
assert!(!seed.iter().all(|&x| x == 0),
655-
"XorShiftRng.reseed called with an all zero seed.");
656-
657-
self.x = w(seed[0]);
658-
self.y = w(seed[1]);
659-
self.z = w(seed[2]);
660-
self.w = w(seed[3]);
661-
}
662-
663-
/// Create a new XorShiftRng. This will panic if `seed` is entirely 0.
664-
fn from_seed(seed: [u32; 4]) -> XorShiftRng {
665-
assert!(!seed.iter().all(|&x| x == 0),
666-
"XorShiftRng::from_seed called with an all zero seed.");
667-
668-
XorShiftRng {
669-
x: w(seed[0]),
670-
y: w(seed[1]),
671-
z: w(seed[2]),
672-
w: w(seed[3]),
673-
}
674-
}
675-
}
676-
677-
impl Rand for XorShiftRng {
678-
fn rand<R: Rng>(rng: &mut R) -> XorShiftRng {
679-
let mut tuple: (u32, u32, u32, u32) = rng.gen();
680-
while tuple == (0, 0, 0, 0) {
681-
tuple = rng.gen();
682-
}
683-
let (x, y, z, w_) = tuple;
684-
XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) }
685-
}
686-
}
687-
688608
/// A wrapper for generating floating point numbers uniformly in the
689609
/// open interval `(0,1)` (not including either endpoint).
690610
///
@@ -766,6 +686,25 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
766686
}
767687
}
768688

689+
/// The standard RNG. This is designed to be efficient on the current
690+
/// platform.
691+
#[derive(Copy, Clone)]
692+
pub struct WeakRng {
693+
rng: InnerWeakRng,
694+
}
695+
696+
impl Rng for WeakRng {
697+
#[inline]
698+
fn next_u32(&mut self) -> u32 {
699+
self.rng.next_u32()
700+
}
701+
702+
#[inline]
703+
fn next_u64(&mut self) -> u64 {
704+
self.rng.next_u64()
705+
}
706+
}
707+
769708
/// Create a weak random number generator with a default algorithm and seed.
770709
///
771710
/// It returns the fastest `Rng` algorithm currently available in Rust without
@@ -775,9 +714,9 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
775714
///
776715
/// This will read randomness from the operating system to seed the
777716
/// generator.
778-
pub fn weak_rng() -> XorShiftRng {
717+
pub fn weak_rng() -> WeakRng {
779718
match OsRng::new() {
780-
Ok(mut r) => r.gen(),
719+
Ok(mut os_rnd) => WeakRng { rng: os_rnd.gen() },
781720
Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e)
782721
}
783722
}

0 commit comments

Comments
 (0)