Skip to content

Commit

Permalink
implement xorshift128+
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurprs committed Jul 17, 2015
1 parent e61752f commit 8a8cdcc
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 139 deletions.
88 changes: 38 additions & 50 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,52 @@
extern crate test;
extern crate rand;

const RAND_BENCH_N: u64 = 100;

mod distributions;

use std::mem::size_of;
use test::{black_box, Bencher};
use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng};
use rand::{OsRng, weak_rng};
use test::Bencher;
use rand::{weak_rng, Rng};

#[bench]
fn rand_xorshift(b: &mut Bencher) {
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}

#[bench]
fn rand_isaac(b: &mut Bencher) {
let mut rng: IsaacRng = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}

#[bench]
fn rand_isaac64(b: &mut Bencher) {
let mut rng: Isaac64Rng = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}

#[bench]
fn rand_std(b: &mut Bencher) {
let mut rng = StdRng::new().unwrap();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<usize>());
}
});
b.bytes = size_of::<usize>() as u64 * RAND_BENCH_N;
}
pub const RAND_BENCH_N: u64 = 100;

#[bench]
fn rand_shuffle_100(b: &mut Bencher) {
let mut rng = weak_rng();
let x : &mut [usize] = &mut [1; 100];
b.iter(|| {
rng.shuffle(x);
rng.shuffle(x)
})
}

mod algorithms {
use test::{black_box, Bencher};
use std::mem::size_of;
use rand::{OsRng, XorShift64Rng, XorShift128PRng, IsaacRng, Isaac64Rng, Rng, ChaChaRng};

use super::*;

macro_rules! impl_bench {
($result_ty: ty: $fn_name: ident, $hasher: ident) => (
#[bench]
fn $fn_name(b: &mut Bencher) {
let mut rng: $hasher = OsRng::new().unwrap().gen();
b.iter(|| {
for _ in 0..RAND_BENCH_N {
black_box(rng.gen::<$result_ty>());
}
});
b.bytes = size_of::<$result_ty>() as u64 * RAND_BENCH_N;
}
)
}

impl_bench!(u32: xorshift_u32, XorShift64Rng);
impl_bench!(u64: xorshift_u64, XorShift64Rng);
impl_bench!(u32: xorshiftp_u32, XorShift128PRng);
impl_bench!(u64: xorshiftp_u64, XorShift128PRng);
impl_bench!(u32: isaac_u32, IsaacRng);
impl_bench!(u64: isaac_u64, IsaacRng);
impl_bench!(u32: isaac64_u32, Isaac64Rng);
impl_bench!(u64: isaac64_u64, Isaac64Rng);
impl_bench!(u32: chacha_u32, ChaChaRng);
impl_bench!(u64: chacha_u64, ChaChaRng);
}
117 changes: 28 additions & 89 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,25 @@ pub use os::OsRng;

pub use isaac::{IsaacRng, Isaac64Rng};
pub use chacha::ChaChaRng;
pub use xorshift::{XorShift64Rng, XorShift128PRng};

#[cfg(target_pointer_width = "32")]
use IsaacRng as IsaacWordRng;
#[cfg(target_pointer_width = "64")]
use Isaac64Rng as IsaacWordRng;

#[cfg(target_pointer_width = "32")]
use XorShift64Rng as InnerWeakRng;
#[cfg(target_pointer_width = "64")]
use XorShift128PRng as InnerWeakRng;

use distributions::{Range, IndependentSample};
use distributions::range::SampleRange;

pub mod distributions;
pub mod isaac;
pub mod chacha;
pub mod xorshift;
pub mod reseeding;
mod rand_impls;
pub mod os;
Expand Down Expand Up @@ -598,93 +605,6 @@ pub trait SeedableRng<Seed>: Rng {
fn from_seed(seed: Seed) -> Self;
}

/// An Xorshift[1] random number
/// generator.
///
/// The Xorshift algorithm is not suitable for cryptographic purposes
/// but is very fast. If you do not know for sure that it fits your
/// requirements, use a more secure one such as `IsaacRng` or `OsRng`.
///
/// [1]: Marsaglia, George (July 2003). ["Xorshift
/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of
/// Statistical Software*. Vol. 8 (Issue 14).
#[allow(missing_copy_implementations)]
#[derive(Clone)]
pub struct XorShiftRng {
x: w32,
y: w32,
z: w32,
w: w32,
}

impl XorShiftRng {
/// Creates a new XorShiftRng instance which is not seeded.
///
/// The initial values of this RNG are constants, so all generators created
/// by this function will yield the same stream of random numbers. It is
/// highly recommended that this is created through `SeedableRng` instead of
/// this function
pub fn new_unseeded() -> XorShiftRng {
XorShiftRng {
x: w(0x193a6754),
y: w(0xa8a7d469),
z: w(0x97830e05),
w: w(0x113ba7bb),
}
}
}

impl Rng for XorShiftRng {
#[inline]
fn next_u32(&mut self) -> u32 {
let x = self.x;
let t = x ^ (x << 11);
self.x = self.y;
self.y = self.z;
self.z = self.w;
let w_ = self.w;
self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
self.w.0
}
}

impl SeedableRng<[u32; 4]> for XorShiftRng {
/// Reseed an XorShiftRng. This will panic if `seed` is entirely 0.
fn reseed(&mut self, seed: [u32; 4]) {
assert!(!seed.iter().all(|&x| x == 0),
"XorShiftRng.reseed called with an all zero seed.");

self.x = w(seed[0]);
self.y = w(seed[1]);
self.z = w(seed[2]);
self.w = w(seed[3]);
}

/// Create a new XorShiftRng. This will panic if `seed` is entirely 0.
fn from_seed(seed: [u32; 4]) -> XorShiftRng {
assert!(!seed.iter().all(|&x| x == 0),
"XorShiftRng::from_seed called with an all zero seed.");

XorShiftRng {
x: w(seed[0]),
y: w(seed[1]),
z: w(seed[2]),
w: w(seed[3]),
}
}
}

impl Rand for XorShiftRng {
fn rand<R: Rng>(rng: &mut R) -> XorShiftRng {
let mut tuple: (u32, u32, u32, u32) = rng.gen();
while tuple == (0, 0, 0, 0) {
tuple = rng.gen();
}
let (x, y, z, w_) = tuple;
XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) }
}
}

/// A wrapper for generating floating point numbers uniformly in the
/// open interval `(0,1)` (not including either endpoint).
///
Expand Down Expand Up @@ -766,6 +686,25 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
}
}

/// The standard RNG. This is designed to be efficient on the current
/// platform.
#[derive(Copy, Clone)]
pub struct WeakRng {
rng: InnerWeakRng,
}

impl Rng for WeakRng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
}

#[inline]
fn next_u64(&mut self) -> u64 {
self.rng.next_u64()
}
}

/// Create a weak random number generator with a default algorithm and seed.
///
/// It returns the fastest `Rng` algorithm currently available in Rust without
Expand All @@ -775,9 +714,9 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
///
/// This will read randomness from the operating system to seed the
/// generator.
pub fn weak_rng() -> XorShiftRng {
pub fn weak_rng() -> WeakRng {
match OsRng::new() {
Ok(mut r) => r.gen(),
Ok(mut os_rnd) => WeakRng { rng: os_rnd.gen() },
Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e)
}
}
Expand Down
Loading

0 comments on commit 8a8cdcc

Please sign in to comment.