v2 / vlib / rand / sys / system_rng_test.v
369 lines · 342 sloc · 8.26 KB · 9f3f1291e8936cc90c7c1abe66a672ac1173d601
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 // This assumes that C.rand() produces uniform results to begin with.
73 // If the failure persists, report an issue on GitHub
74 ranges := [14019545, 80240, 130]
75 for seed in seeds {
76 seed_data := [seed]
77 mut rng := &rand.PRNG(&sys.SysRNG{})
78 rng.seed(seed_data)
79 for range in ranges {
80 check_uniformity_u64(mut rng, u64(range))
81 }
82 }
83}
84
85fn check_uniformity_f64(mut rng rand.PRNG) {
86 expected_mean := 0.5
87 mut variance := 0.0
88 for _ in 0 .. sample_size {
89 diff := rng.f64() - expected_mean
90 variance += diff * diff
91 }
92 variance /= sample_size - 1
93 sigma := math.sqrt(variance)
94 expected_sigma := inv_sqrt_12
95 error := (sigma - expected_sigma) / expected_sigma
96 assert math.abs(error) < stats_epsilon
97}
98
99fn test_sys_rng_uniformity_f64() {
100 // The f64 version
101 for seed in seeds {
102 seed_data := [seed]
103 mut rng := &rand.PRNG(&sys.SysRNG{})
104 rng.seed(seed_data)
105 check_uniformity_f64(mut rng)
106 }
107}
108
109fn test_sys_rng_u32n() {
110 max := u32(16384)
111 for seed in seeds {
112 seed_data := [seed]
113 mut rng := &rand.PRNG(&sys.SysRNG{})
114 rng.seed(seed_data)
115 for _ in 0 .. range_limit {
116 value := rng.u32n(max) or { panic("Couldn't obtain u32") }
117 assert value >= 0
118 assert value < max
119 }
120 }
121}
122
123fn test_sys_rng_u64n() {
124 max := u64(379091181005)
125 for seed in seeds {
126 seed_data := [seed]
127 mut rng := &rand.PRNG(&sys.SysRNG{})
128 rng.seed(seed_data)
129 for _ in 0 .. range_limit {
130 value := rng.u64n(max) or { panic("Couldn't obtain u64") }
131 assert value >= 0
132 assert value < max
133 }
134 }
135}
136
137fn test_sys_rng_u32_in_range() {
138 max := u32(484468466)
139 min := u32(316846)
140 for seed in seeds {
141 seed_data := [seed]
142 mut rng := &rand.PRNG(&sys.SysRNG{})
143 rng.seed(seed_data)
144 for _ in 0 .. range_limit {
145 value := rng.u32_in_range(min, max) or { panic("Couldn't obtain u32 in range") }
146 assert value >= min
147 assert value < max
148 }
149 }
150}
151
152fn test_sys_rng_u64_in_range() {
153 max := u64(216468454685163)
154 min := u64(6848646868)
155 for seed in seeds {
156 seed_data := [seed]
157 mut rng := &rand.PRNG(&sys.SysRNG{})
158 rng.seed(seed_data)
159 for _ in 0 .. range_limit {
160 value := rng.u64_in_range(min, max) or { panic("Couldn't obtain u64 in range") }
161 assert value >= min
162 assert value < max
163 }
164 }
165}
166
167fn test_sys_rng_intn() {
168 max := 2525642
169 for seed in seeds {
170 seed_data := [seed]
171 mut rng := &rand.PRNG(&sys.SysRNG{})
172 rng.seed(seed_data)
173 for _ in 0 .. range_limit {
174 value := rng.intn(max) or { panic("Couldn't obtain int") }
175 assert value >= 0
176 assert value < max
177 }
178 }
179}
180
181fn test_sys_rng_i32n() {
182 max := i32(2525642)
183 for seed in seeds {
184 seed_data := [seed]
185 mut rng := &rand.PRNG(&sys.SysRNG{})
186 rng.seed(seed_data)
187 for _ in 0 .. range_limit {
188 value := rng.i32n(max) or { panic("Couldn't obtain i32") }
189 assert value >= 0
190 assert value < max
191 }
192 }
193}
194
195fn test_sys_rng_i64n() {
196 max := i64(3246727724653636)
197 for seed in seeds {
198 seed_data := [seed]
199 mut rng := &rand.PRNG(&sys.SysRNG{})
200 rng.seed(seed_data)
201 for _ in 0 .. range_limit {
202 value := rng.i64n(max) or { panic("Couldn't obtain i64") }
203 assert value >= 0
204 assert value < max
205 }
206 }
207}
208
209fn test_sys_rng_int_in_range() {
210 min := -4252
211 max := 23054962
212 for seed in seeds {
213 seed_data := [seed]
214 mut rng := &rand.PRNG(&sys.SysRNG{})
215 rng.seed(seed_data)
216 for _ in 0 .. range_limit {
217 value := rng.int_in_range(min, max) or { panic("Couldn't obtain int in range") }
218 assert value >= min
219 assert value < max
220 }
221 }
222}
223
224fn test_sys_rng_i32_in_range() {
225 min := i32(-4252)
226 max := i32(23054962)
227 for seed in seeds {
228 seed_data := [seed]
229 mut rng := &rand.PRNG(&sys.SysRNG{})
230 rng.seed(seed_data)
231 for _ in 0 .. range_limit {
232 value := rng.i32_in_range(min, max) or { panic("Couldn't obtain i32 in range") }
233 assert value >= min
234 assert value < max
235 }
236 }
237}
238
239fn test_sys_rng_i64_in_range() {
240 min := i64(-24095)
241 max := i64(324058)
242 for seed in seeds {
243 seed_data := [seed]
244 mut rng := &rand.PRNG(&sys.SysRNG{})
245 rng.seed(seed_data)
246 for _ in 0 .. range_limit {
247 value := rng.i64_in_range(min, max) or { panic("Couldn't obtain i64 in range") }
248 assert value >= min
249 assert value < max
250 }
251 }
252}
253
254fn test_sys_rng_int31() {
255 max_u31 := int(0x7FFFFFFF)
256 sign_mask := int(u32(0x80000000))
257 for seed in seeds {
258 seed_data := [seed]
259 mut rng := &rand.PRNG(&sys.SysRNG{})
260 rng.seed(seed_data)
261 for _ in 0 .. range_limit {
262 value := rng.int31()
263 assert value >= 0
264 assert value <= max_u31
265 // This statement ensures that the sign bit is zero
266 assert (value & sign_mask) == 0
267 }
268 }
269}
270
271fn test_sys_rng_int63() {
272 max_u63 := i64(0x7FFFFFFFFFFFFFFF)
273 sign_mask := i64(u64(0x8000000000000000))
274 for seed in seeds {
275 seed_data := [seed]
276 mut rng := &rand.PRNG(&sys.SysRNG{})
277 rng.seed(seed_data)
278 for _ in 0 .. range_limit {
279 value := rng.int63()
280 assert value >= 0
281 assert value <= max_u63
282 assert (value & sign_mask) == 0
283 }
284 }
285}
286
287fn test_sys_rng_f32() {
288 for seed in seeds {
289 seed_data := [seed]
290 mut rng := &rand.PRNG(&sys.SysRNG{})
291 rng.seed(seed_data)
292 for _ in 0 .. range_limit {
293 value := rng.f32()
294 assert value >= 0.0
295 assert value < 1.0
296 }
297 }
298}
299
300fn test_sys_rng_f64() {
301 for seed in seeds {
302 seed_data := [seed]
303 mut rng := &rand.PRNG(&sys.SysRNG{})
304 rng.seed(seed_data)
305 for _ in 0 .. range_limit {
306 value := rng.f64()
307 assert value >= 0.0
308 assert value < 1.0
309 }
310 }
311}
312
313fn test_sys_rng_f32n() {
314 max := f32(357.0)
315 for seed in seeds {
316 seed_data := [seed]
317 mut rng := &rand.PRNG(&sys.SysRNG{})
318 rng.seed(seed_data)
319 for _ in 0 .. range_limit {
320 value := rng.f32n(max) or { panic("Couldn't obtain f32") }
321 assert value >= 0.0
322 assert value < max
323 }
324 }
325}
326
327fn test_sys_rng_f64n() {
328 max := 1.52e6
329 for seed in seeds {
330 seed_data := [seed]
331 mut rng := &rand.PRNG(&sys.SysRNG{})
332 rng.seed(seed_data)
333 for _ in 0 .. range_limit {
334 value := rng.f64n(max) or { panic("Couldn't obtain f64") }
335 assert value >= 0.0
336 assert value < max
337 }
338 }
339}
340
341fn test_sys_rng_f32_in_range() {
342 min := f32(-24.0)
343 max := f32(125.0)
344 for seed in seeds {
345 seed_data := [seed]
346 mut rng := &rand.PRNG(&sys.SysRNG{})
347 rng.seed(seed_data)
348 for _ in 0 .. range_limit {
349 value := rng.f32_in_range(min, max) or { panic("Couldn't obtain f32 in range") }
350 assert value >= min
351 assert value < max
352 }
353 }
354}
355
356fn test_sys_rng_f64_in_range() {
357 min := -548.7
358 max := 5015.2
359 for seed in seeds {
360 seed_data := [seed]
361 mut rng := &rand.PRNG(&sys.SysRNG{})
362 rng.seed(seed_data)
363 for _ in 0 .. range_limit {
364 value := rng.f64_in_range(min, max) or { panic("Couldn't obtain f64 in range") }
365 assert value >= min
366 assert value < max
367 }
368 }
369}
370