v / vlib / rand / sys / system_rng_test.v
381 lines · 354 sloc · 8.66 KB · 8fd2094bf98944a2aff9c00c3ee04b60174d2dd4
Raw
1import math
2import rand
3import rand.sys
4
5const range_limit = 40
6const value_count = 1000
7const seeds = [u32(42), 256]
8
9const sample_size = 1000
10const stats_epsilon = 0.05
11const inv_sqrt_12 = 1.0 / math.sqrt(12)
12
13fn get_n_randoms(n int, mut r rand.PRNG) []int {
14 mut ints := []int{cap: n}
15 for _ in 0 .. n {
16 ints << r.int()
17 }
18 return ints
19}
20
21fn test_sys_rng_reproducibility() {
22 // Note that C.srand() sets the seed globally.
23 // So the order of seeding matters. It is recommended
24 // to obtain all necessary data first, then set the
25 // seed for another batch of data.
26 for seed in seeds {
27 seed_data := [seed]
28 mut r1 := &rand.PRNG(&sys.SysRNG{})
29 mut r2 := &rand.PRNG(&sys.SysRNG{})
30 r1.seed(seed_data)
31 ints1 := get_n_randoms(value_count, mut r1)
32 r2.seed(seed_data)
33 ints2 := get_n_randoms(value_count, mut r2)
34 assert ints1 == ints2
35 }
36}
37
38fn test_sys_rng_variability() {
39 // If this test fails and if it is certainly not the implementation
40 // at fault, try changing the seed values. Repeated values are
41 // improbable but not impossible.
42 for seed in seeds {
43 seed_data := [seed]
44 mut rng := &rand.PRNG(&sys.SysRNG{})
45 rng.seed(seed_data)
46 mut values := []u64{cap: value_count}
47 for i in 0 .. value_count {
48 value := rng.u64()
49 assert value !in values
50 assert values.len == i
51 values << value
52 }
53 }
54}
55
56fn check_uniformity_u64(mut rng rand.PRNG, range u64) {
57 range_f64 := f64(range)
58 expected_mean := range_f64 / 2.0
59 mut variance := 0.0
60 for _ in 0 .. sample_size {
61 diff := f64(rng.u64n(range) or { panic("Couldn't obtain u64") }) - expected_mean
62 variance += diff * diff
63 }
64 variance /= sample_size - 1
65 sigma := math.sqrt(variance)
66 expected_sigma := range_f64 * inv_sqrt_12
67 error := (sigma - expected_sigma) / expected_sigma
68 assert math.abs(error) < stats_epsilon
69}
70
71fn test_sys_rng_uniformity_u64() {
72 $if windows {
73 // On Windows, C.rand() has RAND_MAX = 32767 (15 bits). The XOR-based
74 // extension to u64 is inherently biased, so this uniformity check
75 // cannot pass with the system RNG.
76 return
77 }
78 // This assumes that C.rand() produces uniform results to begin with.
79 // If the failure persists, report an issue on GitHub
80 ranges := [14019545, 80240, 130]
81 for seed in seeds {
82 seed_data := [seed]
83 mut rng := &rand.PRNG(&sys.SysRNG{})
84 rng.seed(seed_data)
85 for range in ranges {
86 check_uniformity_u64(mut rng, u64(range))
87 }
88 }
89}
90
91fn check_uniformity_f64(mut rng rand.PRNG) {
92 expected_mean := 0.5
93 mut variance := 0.0
94 for _ in 0 .. sample_size {
95 diff := rng.f64() - expected_mean
96 variance += diff * diff
97 }
98 variance /= sample_size - 1
99 sigma := math.sqrt(variance)
100 expected_sigma := inv_sqrt_12
101 error := (sigma - expected_sigma) / expected_sigma
102 assert math.abs(error) < stats_epsilon
103}
104
105fn test_sys_rng_uniformity_f64() {
106 $if windows {
107 // See test_sys_rng_uniformity_u64 above: Windows C.rand() has a
108 // 15-bit range, so the derived f64 distribution is not uniform enough
109 // to pass the statistical check.
110 return
111 }
112 // The f64 version
113 for seed in seeds {
114 seed_data := [seed]
115 mut rng := &rand.PRNG(&sys.SysRNG{})
116 rng.seed(seed_data)
117 check_uniformity_f64(mut rng)
118 }
119}
120
121fn test_sys_rng_u32n() {
122 max := u32(16384)
123 for seed in seeds {
124 seed_data := [seed]
125 mut rng := &rand.PRNG(&sys.SysRNG{})
126 rng.seed(seed_data)
127 for _ in 0 .. range_limit {
128 value := rng.u32n(max) or { panic("Couldn't obtain u32") }
129 assert value >= 0
130 assert value < max
131 }
132 }
133}
134
135fn test_sys_rng_u64n() {
136 max := u64(379091181005)
137 for seed in seeds {
138 seed_data := [seed]
139 mut rng := &rand.PRNG(&sys.SysRNG{})
140 rng.seed(seed_data)
141 for _ in 0 .. range_limit {
142 value := rng.u64n(max) or { panic("Couldn't obtain u64") }
143 assert value >= 0
144 assert value < max
145 }
146 }
147}
148
149fn test_sys_rng_u32_in_range() {
150 max := u32(484468466)
151 min := u32(316846)
152 for seed in seeds {
153 seed_data := [seed]
154 mut rng := &rand.PRNG(&sys.SysRNG{})
155 rng.seed(seed_data)
156 for _ in 0 .. range_limit {
157 value := rng.u32_in_range(min, max) or { panic("Couldn't obtain u32 in range") }
158 assert value >= min
159 assert value < max
160 }
161 }
162}
163
164fn test_sys_rng_u64_in_range() {
165 max := u64(216468454685163)
166 min := u64(6848646868)
167 for seed in seeds {
168 seed_data := [seed]
169 mut rng := &rand.PRNG(&sys.SysRNG{})
170 rng.seed(seed_data)
171 for _ in 0 .. range_limit {
172 value := rng.u64_in_range(min, max) or { panic("Couldn't obtain u64 in range") }
173 assert value >= min
174 assert value < max
175 }
176 }
177}
178
179fn test_sys_rng_intn() {
180 max := 2525642
181 for seed in seeds {
182 seed_data := [seed]
183 mut rng := &rand.PRNG(&sys.SysRNG{})
184 rng.seed(seed_data)
185 for _ in 0 .. range_limit {
186 value := rng.intn(max) or { panic("Couldn't obtain int") }
187 assert value >= 0
188 assert value < max
189 }
190 }
191}
192
193fn test_sys_rng_i32n() {
194 max := i32(2525642)
195 for seed in seeds {
196 seed_data := [seed]
197 mut rng := &rand.PRNG(&sys.SysRNG{})
198 rng.seed(seed_data)
199 for _ in 0 .. range_limit {
200 value := rng.i32n(max) or { panic("Couldn't obtain i32") }
201 assert value >= 0
202 assert value < max
203 }
204 }
205}
206
207fn test_sys_rng_i64n() {
208 max := i64(3246727724653636)
209 for seed in seeds {
210 seed_data := [seed]
211 mut rng := &rand.PRNG(&sys.SysRNG{})
212 rng.seed(seed_data)
213 for _ in 0 .. range_limit {
214 value := rng.i64n(max) or { panic("Couldn't obtain i64") }
215 assert value >= 0
216 assert value < max
217 }
218 }
219}
220
221fn test_sys_rng_int_in_range() {
222 min := -4252
223 max := 23054962
224 for seed in seeds {
225 seed_data := [seed]
226 mut rng := &rand.PRNG(&sys.SysRNG{})
227 rng.seed(seed_data)
228 for _ in 0 .. range_limit {
229 value := rng.int_in_range(min, max) or { panic("Couldn't obtain int in range") }
230 assert value >= min
231 assert value < max
232 }
233 }
234}
235
236fn test_sys_rng_i32_in_range() {
237 min := i32(-4252)
238 max := i32(23054962)
239 for seed in seeds {
240 seed_data := [seed]
241 mut rng := &rand.PRNG(&sys.SysRNG{})
242 rng.seed(seed_data)
243 for _ in 0 .. range_limit {
244 value := rng.i32_in_range(min, max) or { panic("Couldn't obtain i32 in range") }
245 assert value >= min
246 assert value < max
247 }
248 }
249}
250
251fn test_sys_rng_i64_in_range() {
252 min := i64(-24095)
253 max := i64(324058)
254 for seed in seeds {
255 seed_data := [seed]
256 mut rng := &rand.PRNG(&sys.SysRNG{})
257 rng.seed(seed_data)
258 for _ in 0 .. range_limit {
259 value := rng.i64_in_range(min, max) or { panic("Couldn't obtain i64 in range") }
260 assert value >= min
261 assert value < max
262 }
263 }
264}
265
266fn test_sys_rng_int31() {
267 max_u31 := int(0x7FFFFFFF)
268 sign_mask := int(u32(0x80000000))
269 for seed in seeds {
270 seed_data := [seed]
271 mut rng := &rand.PRNG(&sys.SysRNG{})
272 rng.seed(seed_data)
273 for _ in 0 .. range_limit {
274 value := rng.int31()
275 assert value >= 0
276 assert value <= max_u31
277 // This statement ensures that the sign bit is zero
278 assert (value & sign_mask) == 0
279 }
280 }
281}
282
283fn test_sys_rng_int63() {
284 max_u63 := i64(0x7FFFFFFFFFFFFFFF)
285 sign_mask := i64(u64(0x8000000000000000))
286 for seed in seeds {
287 seed_data := [seed]
288 mut rng := &rand.PRNG(&sys.SysRNG{})
289 rng.seed(seed_data)
290 for _ in 0 .. range_limit {
291 value := rng.int63()
292 assert value >= 0
293 assert value <= max_u63
294 assert (value & sign_mask) == 0
295 }
296 }
297}
298
299fn test_sys_rng_f32() {
300 for seed in seeds {
301 seed_data := [seed]
302 mut rng := &rand.PRNG(&sys.SysRNG{})
303 rng.seed(seed_data)
304 for _ in 0 .. range_limit {
305 value := rng.f32()
306 assert value >= 0.0
307 assert value < 1.0
308 }
309 }
310}
311
312fn test_sys_rng_f64() {
313 for seed in seeds {
314 seed_data := [seed]
315 mut rng := &rand.PRNG(&sys.SysRNG{})
316 rng.seed(seed_data)
317 for _ in 0 .. range_limit {
318 value := rng.f64()
319 assert value >= 0.0
320 assert value < 1.0
321 }
322 }
323}
324
325fn test_sys_rng_f32n() {
326 max := f32(357.0)
327 for seed in seeds {
328 seed_data := [seed]
329 mut rng := &rand.PRNG(&sys.SysRNG{})
330 rng.seed(seed_data)
331 for _ in 0 .. range_limit {
332 value := rng.f32n(max) or { panic("Couldn't obtain f32") }
333 assert value >= 0.0
334 assert value < max
335 }
336 }
337}
338
339fn test_sys_rng_f64n() {
340 max := 1.52e6
341 for seed in seeds {
342 seed_data := [seed]
343 mut rng := &rand.PRNG(&sys.SysRNG{})
344 rng.seed(seed_data)
345 for _ in 0 .. range_limit {
346 value := rng.f64n(max) or { panic("Couldn't obtain f64") }
347 assert value >= 0.0
348 assert value < max
349 }
350 }
351}
352
353fn test_sys_rng_f32_in_range() {
354 min := f32(-24.0)
355 max := f32(125.0)
356 for seed in seeds {
357 seed_data := [seed]
358 mut rng := &rand.PRNG(&sys.SysRNG{})
359 rng.seed(seed_data)
360 for _ in 0 .. range_limit {
361 value := rng.f32_in_range(min, max) or { panic("Couldn't obtain f32 in range") }
362 assert value >= min
363 assert value < max
364 }
365 }
366}
367
368fn test_sys_rng_f64_in_range() {
369 min := -548.7
370 max := 5015.2
371 for seed in seeds {
372 seed_data := [seed]
373 mut rng := &rand.PRNG(&sys.SysRNG{})
374 rng.seed(seed_data)
375 for _ in 0 .. range_limit {
376 value := rng.f64_in_range(min, max) or { panic("Couldn't obtain f64 in range") }
377 assert value >= min
378 assert value < max
379 }
380 }
381}
382