v2 / vlib / rand / mt19937 / mt19937_test.v
327 lines · 301 sloc · 7.54 KB · 9e1ea477b10ef0b896b674d32da892e694e59c36
Raw
1import math
2import rand
3import rand.mt19937
4import rand.seed
5
6const range_limit = 40
7const value_count = 1000
8const seeds = [[u32(0xcafebabe), u32(0xdeadbeef)], [u32(0xc0de), u32(0xfeed)]]
9
10const sample_size = 1000
11const stats_epsilon = 0.05
12const inv_sqrt_12 = 1.0 / math.sqrt(12)
13
14fn mt19937_basic_test() {
15 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
16 rng.seed([u32(0xdeadbeef)])
17 target := [u32(956529277), 3842322136, 3319553134, 1843186657, 2704993644, 595827513, 938518626,
18 1676224337, 3221315650, 1819026461]
19 for i := 0; i < 10; i++ {
20 assert target[i] == rng.u32()
21 }
22}
23
24fn gen_randoms(seed_data []u32, bound int) []u64 {
25 bound_u64 := u64(bound)
26 mut randoms := []u64{len: (20)}
27 mut rnd := &rand.PRNG(&mt19937.MT19937RNG{})
28 rnd.seed(seed_data)
29 for i in 0 .. 20 {
30 randoms[i] = rnd.u64n(bound_u64) or { panic("Couldn't obtain random u64") }
31 }
32 return randoms
33}
34
35fn test_mt19937_reproducibility() {
36 seed_data := seed.time_seed_array(2)
37 randoms1 := gen_randoms(seed_data, 1000)
38 randoms2 := gen_randoms(seed_data, 1000)
39 assert randoms1.len == randoms2.len
40 len := randoms1.len
41 for i in 0 .. len {
42 assert randoms1[i] == randoms2[i]
43 }
44}
45
46fn test_mt19937_variability() {
47 // If this test fails and if it is certainly not the implementation
48 // at fault, try changing the seed values. Repeated values are
49 // improbable but not impossible.
50 for seed in seeds {
51 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
52 rng.seed(seed)
53 mut values := []u64{cap: value_count}
54 for i in 0 .. value_count {
55 value := rng.u64()
56 assert value !in values
57 assert values.len == i
58 values << value
59 }
60 }
61}
62
63fn check_uniformity_u64(mut rng rand.PRNG, range u64) {
64 range_f64 := f64(range)
65 expected_mean := range_f64 / 2.0
66 mut variance := 0.0
67 for _ in 0 .. sample_size {
68 diff := f64(rng.u64n(range) or { panic("Couldn't obtain random u64") }) - expected_mean
69 variance += diff * diff
70 }
71 variance /= sample_size - 1
72 sigma := math.sqrt(variance)
73 expected_sigma := range_f64 * inv_sqrt_12
74 error := (sigma - expected_sigma) / expected_sigma
75 assert math.abs(error) < stats_epsilon
76}
77
78fn test_mt19937_uniformity_u64() {
79 ranges := [14019545, 80240, 130]
80 for seed in seeds {
81 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
82 rng.seed(seed)
83 for range in ranges {
84 check_uniformity_u64(mut rng, u64(range))
85 }
86 }
87}
88
89fn check_uniformity_f64(mut rng rand.PRNG) {
90 expected_mean := 0.5
91 mut variance := 0.0
92 for _ in 0 .. sample_size {
93 diff := rng.f64() - expected_mean
94 variance += diff * diff
95 }
96 variance /= sample_size - 1
97 sigma := math.sqrt(variance)
98 expected_sigma := inv_sqrt_12
99 error := (sigma - expected_sigma) / expected_sigma
100 assert math.abs(error) < stats_epsilon
101}
102
103fn test_mt19937_uniformity_f64() {
104 // The f64 version
105 for seed in seeds {
106 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
107 rng.seed(seed)
108 check_uniformity_f64(mut rng)
109 }
110}
111
112fn test_mt19937_u32n() {
113 max := u32(16384)
114 for seed in seeds {
115 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
116 rng.seed(seed)
117 for _ in 0 .. range_limit {
118 value := rng.u32n(max) or { panic("Couldn't obtain random u32") }
119 assert value >= 0
120 assert value < max
121 }
122 }
123}
124
125fn test_mt19937_u64n() {
126 max := u64(379091181005)
127 for seed in seeds {
128 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
129 rng.seed(seed)
130 for _ in 0 .. range_limit {
131 value := rng.u64n(max) or { panic("Couldn't obtain random u64") }
132 assert value >= 0
133 assert value < max
134 }
135 }
136}
137
138fn test_mt19937_u32_in_range() {
139 max := u32(484468466)
140 min := u32(316846)
141 for seed in seeds {
142 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
143 rng.seed(seed)
144 for _ in 0 .. range_limit {
145 value := rng.u32_in_range(min, max) or { panic("Couldn't obtain random u32 in range.") }
146 assert value >= min
147 assert value < max
148 }
149 }
150}
151
152fn test_mt19937_u64_in_range() {
153 max := u64(216468454685163)
154 min := u64(6848646868)
155 for seed in seeds {
156 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
157 rng.seed(seed)
158 for _ in 0 .. range_limit {
159 value := rng.u64_in_range(min, max) or { panic("Couldn't obtain random u64 in range.") }
160 assert value >= min
161 assert value < max
162 }
163 }
164}
165
166fn test_mt19937_int31() {
167 max_u31 := int(0x7FFFFFFF)
168 sign_mask := int(u32(0x80000000))
169 for seed in seeds {
170 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
171 rng.seed(seed)
172 for _ in 0 .. range_limit {
173 value := rng.int31()
174 assert value >= 0
175 assert value <= max_u31
176 // This statement ensures that the sign bit is zero
177 assert (value & sign_mask) == 0
178 }
179 }
180}
181
182fn test_mt19937_int63() {
183 max_u63 := i64(0x7FFFFFFFFFFFFFFF)
184 sign_mask := i64(u64(0x8000000000000000))
185 for seed in seeds {
186 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
187 rng.seed(seed)
188 for _ in 0 .. range_limit {
189 value := rng.int63()
190 assert value >= 0
191 assert value <= max_u63
192 assert (value & sign_mask) == 0
193 }
194 }
195}
196
197fn test_mt19937_intn() {
198 max := 2525642
199 for seed in seeds {
200 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
201 rng.seed(seed)
202 for _ in 0 .. range_limit {
203 value := rng.intn(max) or { panic("Couldn't obtain random int") }
204 assert value >= 0
205 assert value < max
206 }
207 }
208}
209
210fn test_mt19937_i64n() {
211 max := i64(3246727724653636)
212 for seed in seeds {
213 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
214 rng.seed(seed)
215 for _ in 0 .. range_limit {
216 value := rng.i64n(max) or { panic("Couldn't obtain random i64") }
217 assert value >= 0
218 assert value < max
219 }
220 }
221}
222
223fn test_mt19937_int_in_range() {
224 min := -4252
225 max := 1034
226 for seed in seeds {
227 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
228 rng.seed(seed)
229 for _ in 0 .. range_limit {
230 value := rng.int_in_range(min, max) or { panic("Couldn't obtain random int in range.") }
231 assert value >= min
232 assert value < max
233 }
234 }
235}
236
237fn test_mt19937_i64_in_range() {
238 min := i64(-24095)
239 max := i64(324058)
240 for seed in seeds {
241 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
242 rng.seed(seed)
243 for _ in 0 .. range_limit {
244 value := rng.i64_in_range(min, max) or { panic("Couldn't obtain random i64 in range.") }
245 assert value >= min
246 assert value < max
247 }
248 }
249}
250
251fn test_mt19937_f32() {
252 for seed in seeds {
253 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
254 rng.seed(seed)
255 for _ in 0 .. range_limit {
256 value := rng.f32()
257 assert value >= 0.0
258 assert value < 1.0
259 }
260 }
261}
262
263fn test_mt19937_f64() {
264 for seed in seeds {
265 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
266 rng.seed(seed)
267 for _ in 0 .. range_limit {
268 value := rng.f64()
269 assert value >= 0.0
270 assert value < 1.0
271 }
272 }
273}
274
275fn test_mt19937_f32n() {
276 max := f32(357.0)
277 for seed in seeds {
278 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
279 rng.seed(seed)
280 for _ in 0 .. range_limit {
281 value := rng.f32n(max) or { panic("Couldn't obtain random f32") }
282 assert value >= 0.0
283 assert value < max
284 }
285 }
286}
287
288fn test_mt19937_f64n() {
289 max := 1.52e6
290 for seed in seeds {
291 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
292 rng.seed(seed)
293 for _ in 0 .. range_limit {
294 value := rng.f64n(max) or { panic("Couldn't obtain random f64") }
295 assert value >= 0.0
296 assert value < max
297 }
298 }
299}
300
301fn test_mt19937_f32_in_range() {
302 min := f32(-24.0)
303 max := f32(125.0)
304 for seed in seeds {
305 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
306 rng.seed(seed)
307 for _ in 0 .. range_limit {
308 value := rng.f32_in_range(min, max) or { panic("Couldn't obtain random f32 in range.") }
309 assert value >= min
310 assert value < max
311 }
312 }
313}
314
315fn test_mt19937_f64_in_range() {
316 min := -548.7
317 max := 5015.2
318 for seed in seeds {
319 mut rng := &rand.PRNG(&mt19937.MT19937RNG{})
320 rng.seed(seed)
321 for _ in 0 .. range_limit {
322 value := rng.f64_in_range(min, max) or { panic("Couldn't obtain random f64 in range.") }
323 assert value >= min
324 assert value < max
325 }
326 }
327}
328