1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Written by Alexander Stocko <as@coder.gg>
//
// To the extent possible under law, the author has dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// See <LICENSE or http://creativecommons.org/publicdomain/zero/1.0/>

//! Implementation of the high performance xoroshiro128+, xorshift128+, xorshift1024*, and splitmix64 pseudo random number generators.
//!
//! Implements the `Rand`, `Rng`, and `SeedableRng` traits from the [rand crate](https://crates.io/crates/rand).
//!
//! # Usage
//! ```toml
//! [dependencies]
//! xorshift = "0.1"
//! ```
//! ```rust
//! extern crate xorshift;
//! ```
//!
//! # Examples
//! ```rust
//! extern crate time;
//! extern crate xorshift;
//!
//! use time::precise_time_ns;
//! use xorshift::{Rand, Rng, SeedableRng, SplitMix64, Xoroshiro128, Xorshift128, Xorshift1024};
//!
//! fn main() {
//!     // Use the high-resolution performance counter for seeding
//!     let now = precise_time_ns();
//!
//!     // Manually seed a Xorshift128+ PRNG
//!     let states = [now, now];
//!     let mut rng: Xorshift128 = SeedableRng::from_seed(&states[..]);
//!     println!("Xorshift128+ random u64: {}", rng.next_u64());
//!
//!     // Use a SplitMix64 PRNG to seed a Xoroshiro128+ PRNG
//!     let mut sm: SplitMix64 = SeedableRng::from_seed(now);
//!     let mut rng: Xoroshiro128 = Rand::rand(&mut sm);
//!     println!("Xoroshiro128+ random u64: {}", rng.next_u64());
//!
//!     let mut rng: Xorshift1024 = Rand::rand(&mut sm);
//!     println!("Xorshift1024* random u64: {}", rng.next_u64());
//!
//!     // Generate 20 random u32s
//!     let vals = rng.gen_iter::<u32>().take(20).collect::<Vec<u32>>();
//!     println!("Xorshift1024* random u32: {:?}", vals);
//!
//!     // Generate 50 random u64s
//!     let vals = rng.gen_iter::<u64>().take(50).collect::<Vec<u64>>();
//!     println!("Xorshift1024* random u64: {:?}", vals);
//! }
//!
//! ```
//!
//! # Parallelism
//! Applications with little parallelism, should use the Xoroshiro128+ generator.
//! For large scale parallel computations, use Xorshift1024*. Either use the
//! `thread_rng()` function to create generators with the same seed but incremented
//! jump states or explicitly use the jump function to forward generator
//! state.
//!
//! ```rust
//! extern crate xorshift;
//!
//! use std::thread;
//! use xorshift::{Rng, Xorshift1024};
//! use xorshift::thread_rng;
//!
//! fn main() {
//!     let mut threads = Vec::new();
//!
//!     for i in 0..17 {
//!         threads.push(thread::spawn(move || {
//!             let mut r: Xorshift1024 = thread_rng();
//!             println!("Thread: {}, random u64: {}", i, r.next_u64());
//!         }));
//!     }
//!
//!     for child in threads {
//!         let _ = child.join();
//!     }
//! }
//! ```
//!
//!
//! ```rust
//! extern crate time;
//! extern crate xorshift;
//!
//! use std::thread;
//! use time::precise_time_ns;
//! use xorshift::{Rand, Rng, RngJump, SeedableRng, SplitMix64, Xorshift1024};
//!
//! fn main() {
//!     // Use the high-resolution performance counter for seeding
//!     let now = precise_time_ns();
//!
//!     let mut sm: SplitMix64 = SeedableRng::from_seed(now);
//!     let rng: Xorshift1024 = Rand::rand(&mut sm);
//!
//!     let mut threads = Vec::new();
//!
//!     for i in 0..17 {
//!         threads.push(thread::spawn(move || {
//!             let mut r = rng;
//!             r.jump(i);
//!             println!("Thread: {}, random u64: {}", i, r.next_u64());
//!         }));
//!     }
//!
//!     for child in threads {
//!         let _ = child.join();
//!     }
//! }
//! ```
//!

#[macro_use]
extern crate lazy_static;

extern crate rand;

pub mod splitmix64;
pub mod xoroshiro128;
pub mod xorshift128;
pub mod xorshift1024;

pub use splitmix64::SplitMix64;
pub use xoroshiro128::Xoroshiro128;
pub use xorshift128::Xorshift128;
pub use xorshift1024::Xorshift1024;

pub use rand::{Rand, Rng, SeedableRng, StdRng};

use std::sync::atomic::{AtomicUsize, Ordering};

/// A random number generator with jumpable state.
pub trait RngJump {
    /// Forward the state of the random number generator.
    ///
    /// When using the random number generator for parallel computations,
    /// jump the state to avoid biased generation.
    fn jump(&mut self, count: usize);
}


/// Create a jumpable random number generator. Each call increments
/// the generator jump state.
pub fn thread_rng <'a, T: Rand+Rng+RngJump+SeedableRng<&'a [u64]>>() -> T {
    lazy_static! {
        static ref THREAD_RNG_STATE : Vec<u64> = {
            match StdRng::new() {
                Ok(mut r) => r.gen_iter::<u64>().take(16).collect::<Vec<u64>>(),
                Err(e) => panic!("could not initialize seeding rng: {}", e)
            }
        };
        static ref THREAD_RNG_INSTANCE : AtomicUsize = AtomicUsize::new(0);
    };

    let mut rng:T = SeedableRng::from_seed(&(*THREAD_RNG_STATE)[..]);
    rng.jump((*THREAD_RNG_INSTANCE).fetch_add(1, Ordering::SeqCst));

    rng
}


// Taken from the lib.rs in the rand crate.
#[cfg(test)]
mod test {
    pub fn iter_eq<I, J>(i: I, j: J) -> bool
        where I: IntoIterator, J: IntoIterator<Item = I::Item>, I::Item: Eq {

        // make sure the iterators have equal length
        let mut i = i.into_iter();
        let mut j = j.into_iter();
        loop {
            match (i.next(), j.next()) {
                (Some(ref ei), Some(ref ej)) if ei == ej => {}
                (None, None) => return true,
                _ => return false,
            }
        }
    }
}