1const N: usize = 624;
15const M: usize = 397;
16const MATRIX_A: u32 = 0x9908_b0df;
17const UPPER_MASK: u32 = 0x8000_0000;
18const LOWER_MASK: u32 = 0x7fff_ffff;
19const TWO_POW_M32: f64 = 2.328_306_436_538_696_3e-10;
21const I2_32M1: f64 = 2.328_306_437_080_797e-10;
23const BIG: f64 = 134_217_728.0;
25
26pub struct RRng {
28 mt: [u32; N],
29 mti: usize,
30}
31
32impl RRng {
33 pub fn new(seed: i32) -> Self {
39 let mut s = seed as u32;
40 for _ in 0..50 {
41 s = s.wrapping_mul(69069).wrapping_add(1);
42 }
43 s = s.wrapping_mul(69069).wrapping_add(1);
45 let mut mt = [0u32; N];
46 for word in mt.iter_mut() {
47 s = s.wrapping_mul(69069).wrapping_add(1);
48 *word = s;
49 }
50 RRng { mt, mti: N }
51 }
52
53 fn genrand(&mut self) -> u32 {
55 const MAG01: [u32; 2] = [0, MATRIX_A];
56 if self.mti >= N {
57 let mt = &mut self.mt;
58 for kk in 0..(N - M) {
59 let y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
60 mt[kk] = mt[kk + M] ^ (y >> 1) ^ MAG01[(y & 1) as usize];
61 }
62 for kk in (N - M)..(N - 1) {
63 let y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
64 mt[kk] = mt[kk + M - N] ^ (y >> 1) ^ MAG01[(y & 1) as usize];
65 }
66 let y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
67 mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ MAG01[(y & 1) as usize];
68 self.mti = 0;
69 }
70 let mut y = self.mt[self.mti];
71 self.mti += 1;
72 y ^= y >> 11;
73 y ^= (y << 7) & 0x9d2c_5680;
74 y ^= (y << 15) & 0xefc6_0000;
75 y ^= y >> 18;
76 y
77 }
78
79 pub fn unif_rand(&mut self) -> f64 {
81 fixup(self.genrand() as f64 * TWO_POW_M32)
82 }
83
84 pub fn norm_rand(&mut self) -> f64 {
87 let u1 = self.unif_rand();
88 let big_u = (BIG * u1).trunc() + self.unif_rand();
89 qnorm(big_u / BIG)
90 }
91
92 pub fn runif(&mut self, n: usize) -> Vec<f64> {
94 (0..n).map(|_| self.unif_rand()).collect()
95 }
96
97 pub fn rnorm(&mut self, n: usize) -> Vec<f64> {
99 (0..n).map(|_| self.norm_rand()).collect()
100 }
101}
102
103fn fixup(x: f64) -> f64 {
105 if x <= 0.0 {
106 0.5 * I2_32M1
107 } else if 1.0 - x <= 0.0 {
108 1.0 - 0.5 * I2_32M1
109 } else {
110 x
111 }
112}
113
114#[allow(clippy::excessive_precision)]
118pub fn qnorm(p: f64) -> f64 {
119 let q = p - 0.5;
120 if q.abs() <= 0.425 {
121 let r = 0.180625 - q * q;
122 return q
123 * (((((((r * 2509.0809287301226727 + 33430.575583588128105) * r
124 + 67265.770927008700853)
125 * r
126 + 45921.953931549871457)
127 * r
128 + 13731.693765509461125)
129 * r
130 + 1971.5909503065514427)
131 * r
132 + 133.14166789178437745)
133 * r
134 + 3.387132872796366608)
135 / (((((((r * 5226.495278852854561 + 28729.085735721942674) * r
136 + 39307.89580009271061)
137 * r
138 + 21213.794301586595867)
139 * r
140 + 5394.1960214247511077)
141 * r
142 + 687.1870074920579083)
143 * r
144 + 42.313330701600911252)
145 * r
146 + 1.0);
147 }
148 let mut r = if q < 0.0 { p } else { 1.0 - p };
149 r = (-r.ln()).sqrt();
150 let val = if r <= 5.0 {
151 r -= 1.6;
152 (((((((r * 7.7454501427834140764e-4 + 0.0227238449892691845833) * r
153 + 0.24178072517745061177)
154 * r
155 + 1.27045825245236838258)
156 * r
157 + 3.64784832476320460504)
158 * r
159 + 5.7694972214606914055)
160 * r
161 + 4.6303378461565452959)
162 * r
163 + 1.42343711074968357734)
164 / (((((((r * 1.05075007164441684324e-9 + 5.475938084995344946e-4) * r
165 + 0.0151986665636164571966)
166 * r
167 + 0.14810397642748007459)
168 * r
169 + 0.68976733498510000455)
170 * r
171 + 1.6763848301838038494)
172 * r
173 + 2.05319162663775882187)
174 * r
175 + 1.0)
176 } else {
177 r -= 5.0;
178 (((((((r * 2.01033439929228813265e-7 + 2.71155556874348757815e-5) * r
179 + 0.0012426609473880784386)
180 * r
181 + 0.026532189526576123093)
182 * r
183 + 0.29656057182850489123)
184 * r
185 + 1.7848265399172913358)
186 * r
187 + 5.4637849111641143699)
188 * r
189 + 6.6579046435011037772)
190 / (((((((r * 2.04426310338993978564e-15 + 1.4215117583164458887e-7) * r
191 + 1.8463183175100546818e-5)
192 * r
193 + 7.868691311456132591e-4)
194 * r
195 + 0.0148753612908506148525)
196 * r
197 + 0.13692988092273580531)
198 * r
199 + 0.59983220655588793769)
200 * r
201 + 1.0)
202 };
203 if q < 0.0 {
204 -val
205 } else {
206 val
207 }
208}
209
210#[cfg(test)]
211#[allow(clippy::excessive_precision)]
212mod tests {
213 use super::*;
214
215 #[test]
216 fn seed_state_matches_r() {
217 let rng = RRng::new(1);
218 let want_head: [u32; 10] = [
220 4125696813, 3852956682, 3691408899, 4072619880, 1489374793, 865871222, 1734802815,
221 98005428, 268448037, 63650722,
222 ];
223 for (k, &w) in want_head.iter().enumerate() {
224 assert_eq!(rng.mt[k], w, "state[{k}]");
225 }
226 assert_eq!(rng.mt[623], 3605718188, "state[623]");
227 assert_eq!(rng.mti, 624);
228 }
229
230 #[test]
231 fn runif_matches_r() {
232 let mut rng = RRng::new(1);
233 let got = rng.runif(10);
234 let want = [
235 0.26550866314209998,
236 0.37212389963679016,
237 0.57285336335189641,
238 0.90820778999477625,
239 0.2016819310374558,
240 0.89838968496769667,
241 0.94467526860535145,
242 0.66079779248684645,
243 0.62911404389888048,
244 0.061786270467564464,
245 ];
246 for (g, w) in got.iter().zip(want.iter()) {
247 assert_eq!(g, w, "runif seed 1");
248 }
249
250 let mut rng = RRng::new(42);
251 let got = rng.runif(8);
252 let want = [
253 0.91480604349635541,
254 0.93707541329786181,
255 0.28613953478634357,
256 0.83044762606732547,
257 0.64174551889300346,
258 0.51909594913013279,
259 0.73658831464126706,
260 0.13466659723781049,
261 ];
262 for (g, w) in got.iter().zip(want.iter()) {
263 assert_eq!(g, w, "runif seed 42");
264 }
265 }
266
267 #[test]
268 fn rnorm_matches_r() {
269 let mut rng = RRng::new(1);
270 let got = rng.rnorm(10);
271 let want = [
272 -0.62645381074233242,
273 0.18364332422208224,
274 -0.83562861241004716,
275 1.5952808021377916,
276 0.32950777181536051,
277 -0.82046838411801526,
278 0.48742905242848528,
279 0.73832470512921733,
280 0.57578135165349231,
281 -0.30538838715635602,
282 ];
283 for (g, w) in got.iter().zip(want.iter()) {
284 assert_eq!(g, w, "rnorm seed 1");
285 }
286
287 let mut rng = RRng::new(42);
288 let got = rng.rnorm(8);
289 let want = [
290 1.3709584471466685,
291 -0.56469817139608869,
292 0.3631284113373392,
293 0.63286260496104041,
294 0.40426832314099903,
295 -0.10612451609148403,
296 1.5115219974389389,
297 -0.094659038413097557,
298 ];
299 for (g, w) in got.iter().zip(want.iter()) {
300 assert_eq!(g, w, "rnorm seed 42");
301 }
302 }
303
304 #[test]
305 fn qnorm_matches_r() {
306 let probs = [1e-10, 0.0123, 0.25, 0.5, 0.75, 0.9999, 1.0 - 1e-12];
307 let want = [
308 -6.3613409024040557,
309 -2.2476267557951379,
310 -0.67448975019608171,
311 0.0,
312 0.67448975019608171,
313 3.7190164854557084,
314 7.0344869100478356,
315 ];
316 for (&p, &w) in probs.iter().zip(want.iter()) {
317 assert_eq!(qnorm(p), w, "qnorm({p})");
318 }
319 }
320}