Skip to content

Commit dc2fabd

Browse files
authored
Add Xoshiro256++ random number generator (#21)
1 parent 64f3755 commit dc2fabd

File tree

3 files changed

+107
-1
lines changed

3 files changed

+107
-1
lines changed

src/graph/connectivity.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl ConnectivityData {
4545
///
4646
/// Multiple-edges and self-loops are correctly handled.
4747
pub struct ConnectivityGraph<'a> {
48-
// Immutable graph, frozen for the lifetime of the ConnectivityGraph object.
48+
/// Immutable graph, frozen for the lifetime of the ConnectivityGraph object.
4949
pub graph: &'a Graph,
5050
/// ID of a vertex's CC, SCC or 2ECC, whichever applies. Range 1 to num_cc.
5151
pub cc: Vec<usize>,

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Algorithms Cookbook in Rust.
2+
23
pub mod caching;
34
pub mod graph;
45
pub mod math;
56
pub mod order;
67
pub mod range_query;
8+
pub mod rng;
79
pub mod scanner;
810
pub mod string_proc;

src/rng.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//! Pseudorandom number generators (PRNGs).
2+
3+
/// A simple and efficient random number generator.
4+
pub type SmallRng = Xoshiro256PlusPlus;
5+
6+
/// A xoshiro256++ random number generator.
7+
///
8+
/// This is a simplified version of the `SmallRng` implementation from the
9+
/// excellent `rand` crate, keeping only essential features.
10+
///
11+
/// The xoshiro256++ algorithm is not suitable for cryptographic purposes, but
12+
/// is very fast and has excellent statistical properties.
13+
///
14+
/// * Source: [Docs.rs](https://docs.rs/rand/0.8.4/src/rand/rngs/xoshiro256plusplus.rs.html)
15+
/// * Theory: [Xorshift - Wikipedia](https://en.wikipedia.org/wiki/Xorshift)
16+
#[derive(Debug, Clone, PartialEq, Eq)]
17+
pub struct Xoshiro256PlusPlus {
18+
s: [u64; 4],
19+
}
20+
21+
impl Xoshiro256PlusPlus {
22+
/// Construct a new RNG from a 64-bit seed.
23+
pub fn new(mut state: u64) -> Self {
24+
const PHI: u64 = 0x9e3779b97f4a7c15;
25+
let mut seed = <[u64; 4]>::default();
26+
for chunk in &mut seed {
27+
state = state.wrapping_add(PHI);
28+
let mut z = state;
29+
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
30+
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
31+
z = z ^ (z >> 31);
32+
*chunk = z;
33+
}
34+
Self { s: seed }
35+
}
36+
37+
/// Generate a random `u32`.
38+
#[inline]
39+
pub fn next_u32(&mut self) -> u32 {
40+
(self.next_u64() >> 32) as u32
41+
}
42+
43+
/// Generate a random `u64`.
44+
#[inline]
45+
pub fn next_u64(&mut self) -> u64 {
46+
let result_plusplus = self.s[0]
47+
.wrapping_add(self.s[3])
48+
.rotate_left(23)
49+
.wrapping_add(self.s[0]);
50+
51+
let t = self.s[1] << 17;
52+
53+
self.s[2] ^= self.s[0];
54+
self.s[3] ^= self.s[1];
55+
self.s[1] ^= self.s[2];
56+
self.s[0] ^= self.s[3];
57+
58+
self.s[2] ^= t;
59+
60+
self.s[3] = self.s[3].rotate_left(45);
61+
62+
result_plusplus
63+
}
64+
}
65+
66+
#[cfg(test)]
67+
mod tests {
68+
use super::*;
69+
70+
#[test]
71+
fn test_xoshiro256plusplus() {
72+
let mut rng = Xoshiro256PlusPlus::new(42);
73+
assert_eq!(rng.next_u64(), 15021278609987233951);
74+
assert_eq!(rng.next_u64(), 5881210131331364753);
75+
assert_eq!(rng.next_u64(), 18149643915985481100);
76+
assert_eq!(rng.next_u64(), 12933668939759105464);
77+
assert_eq!(rng.next_u64(), 14637574242682825331);
78+
assert_eq!(rng.next_u64(), 10848501901068131965);
79+
assert_eq!(rng.next_u64(), 2312344417745909078);
80+
assert_eq!(rng.next_u64(), 11162538943635311430);
81+
}
82+
83+
#[test]
84+
fn reference() {
85+
let mut rng = Xoshiro256PlusPlus { s: [1, 2, 3, 4] };
86+
// These values were produced with the reference implementation:
87+
// http://xoshiro.di.unimi.it/xoshiro256plusplus.c
88+
let expected = [
89+
41943041,
90+
58720359,
91+
3588806011781223,
92+
3591011842654386,
93+
9228616714210784205,
94+
9973669472204895162,
95+
14011001112246962877,
96+
12406186145184390807,
97+
15849039046786891736,
98+
10450023813501588000,
99+
];
100+
for &e in &expected {
101+
assert_eq!(rng.next_u64(), e);
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)