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
use ;
/// Rapidhash V1 secret[0].
///
/// Use an odd number for incrementing to guarantee the state cycles through the full u64 range.
const RAPID_SECRET_ADD: u64 = 0x2d358dccaa6c78a5;
/// Rapidhash V1 secret[1].
const RAPID_SECRET_XOR: u64 = 0x8bb84b93962eacc9;
/// Folded 64-bit multiply: compute the 128-bit product `a * b` and XOR its high and low 64-bit
/// halves together.
///
/// Vendored from the `rapidhash` crate so that `rapidrand` stays a zero-dependency crate. Keep this
/// bit-for-bit in sync with rapidhash: <https://github.com/hoxxep/rapidhash>.
const
/// Generate a pseudorandom number using rapidhash mixing.
///
/// This PRNG is not a cryptographic random number generator.
///
/// This implementation is equivalent in logic and performance to
/// [wyhash::wyrand](https://github.com/wangyi-fudan/wyhash) and
/// [fastrand](https://docs.rs/fastrand/), but uses rapidhash constants/secrets.
///
/// # Example
/// ```rust
/// use rapidrand::rapidrng;
///
/// let mut state: u64 = 42;
/// let value: u64 = rapidrng(&mut state);
/// ```
pub const
/// Generate a pseudorandom number using rapidhash mixing, with a single constant.
///
/// This PRNG is not a cryptographic random number generator.
///
/// Prefer [`rapidrng`]: it is equally fast and avoids the statistical defect described below.
///
/// # Performance
///
/// This uses a single constant instead of two. In hot loops the compiler hoists both constants
/// into registers and the generated inner loop is identical to [`rapidrng`] (instruction-for-
/// instruction on aarch64), so wall-time performance is the same. The single constant only helps
/// at cold call sites — one fewer 64-bit constant to materialise (a 10-byte `movabs` on x86-64,
/// `mov` + 3×`movk` on aarch64) — and frees one register under register pressure.
///
/// This implementation is equivalent in logic and performance to
/// [wyhash::w1rand](https://github.com/wangyi-fudan/wyhash).
///
/// # Statistical weakness: consecutive repeats
///
/// Reusing the increment constant as the xor constant creates exact consecutive repeats. Whenever
/// the post-increment state satisfies `state & RAPID_SECRET_ADD == 0`, the next increment carries
/// nowhere, so `state + RAPID_SECRET_ADD == state ^ RAPID_SECRET_ADD`. The folded multiply is
/// commutative in its arguments, so the *next* output exactly equals the current one.
///
/// The number of repeat states is 2^z where z is the number of zero bits in the constant, doubled
/// if its top bit is set (the wrapping add discards the carry out of bit 63, freeing that state
/// bit). `RAPID_SECRET_ADD` has 32 set bits and a clear top bit, so exactly 2^32 of the 2^64
/// states trigger this: an identical adjacent output pair once per ~2^32 draws on average — a few
/// seconds of continuous generation — where a truly random stream would produce one every 2^64
/// draws. A different constant cannot avoid this: good multiplicative constants have roughly half
/// their bits set, pinning the rate near 2^-32. Upstream `w1rand` shares the defect (33 set bits,
/// top bit set: also exactly 2^32 repeat states). PractRand and BigCrush do not test adjacent-word
/// equality and pass this generator regardless, but a dedicated test detects the bias within
/// seconds, and any use that treats consecutive outputs as unique (e.g. forming 128-bit values
/// from adjacent draws) inherits it.
///
/// [`rapidrng`]'s two-constant pair has zero states satisfying `state + RAPID_SECRET_ADD ==
/// state ^ RAPID_SECRET_XOR` (the required carry pattern is inconsistent), so it never repeats
/// consecutively.
pub const
/// A random number generator that uses the rapidhash mixing algorithm.
///
/// This deterministic RNG is optimized for speed and throughput. This is not a cryptographic random
/// number generator.
///
/// With the `rand` feature, this RNG implements [`rand_core::Rng`] and [`rand_core::SeedableRng`]
/// on top of [`rapidrng`] and is fully compatible with [`rand`] v0.10.
///
/// # Examples
/// Seed it from `rand`'s thread-local RNG (itself seeded from the OS) with `from_rng`:
///
/// ```rust
/// use rand::{RngExt}; // RngExt brings `.random()`, `.random_range()`, ...
/// use rapidrand::RapidRng;
///
/// let mut rng: RapidRng = rand::make_rng();
///
/// let coin: bool = rng.random();
/// let roll = rng.random_range(1..=6);
/// let value: u32 = rng.random();
/// ```
///
/// For a reproducible stream, seed it from a fixed value instead:
///
/// ```rust
/// use rand::{RngExt, SeedableRng};
/// use rapidrand::RapidRng;
///
/// let mut rng = RapidRng::seed_from_u64(42);
/// let value: u32 = rng.random();
/// ```