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
#![no_std]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
#[cfg(feature = "std")]
mod thread;
pub extern crate random_trait;
pub use random_trait::Random;
#[cfg(feature = "std")]
use thread::FromRawPtr;
#[cfg(feature = "std")]
pub use thread::ThreadFastRng;
use core::mem;
#[cfg(feature = "doc-comment")]
extern crate doc_comment;
#[cfg(feature = "doc-comment")]
doc_comment::doctest!("../README.md");
const PCG_DEFAULT_MULTIPLIER_64: u64 = 6_364_136_223_846_793_005;
pub struct FastRng {
state: u64,
inc: u64,
}
impl FastRng {
#[cfg(feature = "std")]
pub fn new() -> Self {
let (a, b) = time_seed();
Self::seed(a, b)
}
pub fn seed(seed: u64, seq: u64) -> Self {
let init_inc = (seq << 1) | 1;
let init_state = seed + init_inc;
let mut rng = FastRng { state: init_state, inc: init_inc };
rng.state = rng.state.wrapping_mul(PCG_DEFAULT_MULTIPLIER_64).wrapping_add(rng.inc);
rng
}
fn gen_u32(&mut self) -> u32 {
let old_state = self.state;
self.state = self.state.wrapping_mul(PCG_DEFAULT_MULTIPLIER_64).wrapping_add(self.inc);
let xorshift = (((old_state >> 18) ^ old_state) >> 27) as u32;
let rot = (old_state >> 59) as i32;
(xorshift >> rot) | (xorshift << ((-rot) & 31))
}
}
#[cfg(feature = "std")]
pub fn local_rng() -> ThreadFastRng {
use std::cell::RefCell;
thread_local! {
pub static THREAD_FAST_RNG: RefCell<FastRng> = RefCell::new(FastRng::new());
}
let ptr = THREAD_FAST_RNG.with(|r| r.as_ptr());
ThreadFastRng::from_ptr(ptr)
}
#[cfg(feature = "std")]
fn time_seed() -> (u64, u64) {
use std::time;
let now = time::SystemTime::now();
let unix = now.duration_since(time::UNIX_EPOCH).unwrap();
(unix.as_secs(), u64::from(unix.subsec_nanos()))
}
impl Random for FastRng {
type Error = ();
fn try_fill_bytes(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
for chunk in buf.chunks_mut(4) {
let rand: [u8; 4] = unsafe { mem::transmute(self.gen_u32()) };
let len = chunk.len();
chunk.copy_from_slice(&rand[..len]);
}
Ok(())
}
fn get_u32(&mut self) -> u32 {
self.gen_u32()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_local() {
let mut local_rng = local_rng();
let a: u64 = local_rng.gen();
let b: u32 = local_rng.gen();
let c: [u8; 64] = local_rng.gen();
assert_ne!(a, 0);
assert_ne!(b, 0);
assert_ne!(&c[..], &[0u8; 64][..]);
}
#[test]
fn test_float() {
let mut rng = FastRng::new();
let f: f32 = rng.gen();
assert!(f > 0.0 && f < 1.0);
let f: f64 = rng.gen();
assert!(f > 0.0 && f < 1.0);
}
}