v / vlib / rand / random_numbers_test.v
536 lines · 483 sloc · 11.88 KB · 2332ecff4811b8c97dfda8e825170e9397962519
Raw
1import rand
2import rand.splitmix64
3import rand.musl
4import rand.mt19937
5
6const rnd_count = 40
7const seeds = [[u32(42), 0], [u32(256), 0]]
8
9fn get_n_random_ints(seed_data []u32, n int) []int {
10 mut values := []int{cap: n}
11 rand.seed(seed_data)
12 for _ in 0 .. n {
13 values << rand.intn(n) or { panic("Couldn't obtain int") }
14 }
15 return values
16}
17
18fn test_rand_reproducibility() {
19 for seed in seeds {
20 array1 := get_n_random_ints(seed, 1000)
21 array2 := get_n_random_ints(seed, 1000)
22 assert array1.len == array2.len
23 assert array1 == array2
24 }
25}
26
27fn test_rand_u32n() {
28 max := u32(16384)
29 for _ in 0 .. rnd_count {
30 value := rand.u32n(max) or { panic("Couldn't obtain u32") }
31 assert value >= 0
32 assert value < max
33 }
34}
35
36fn test_rand_u64n() {
37 max := u64(379091181005)
38 for _ in 0 .. rnd_count {
39 value := rand.u64n(max) or { panic("Couldn't obtain u64") }
40 assert value >= 0
41 assert value < max
42 }
43}
44
45fn test_rand_u32_in_range() {
46 max := u32(484468466)
47 min := u32(316846)
48 for _ in 0 .. rnd_count {
49 value := rand.u32_in_range(min, max) or { panic("Couldn't obtain u32 in range") }
50 assert value >= min
51 assert value < max
52 }
53}
54
55fn test_rand_u64_in_range() {
56 max := u64(216468454685163)
57 min := u64(6848646868)
58 for _ in 0 .. rnd_count {
59 value := rand.u64_in_range(min, max) or { panic("Couldn't obtain u64 in range") }
60 assert value >= min
61 assert value < max
62 }
63}
64
65fn test_rand_intn() {
66 max := 2525642
67 for _ in 0 .. rnd_count {
68 value := rand.intn(max) or { panic("Couldn't obtain int") }
69 assert value >= 0
70 assert value < max
71 }
72}
73
74fn test_rand_i32n() {
75 max := i32(2525642)
76 for _ in 0 .. rnd_count {
77 value := rand.i32n(max) or { panic("Couldn't obtain i32") }
78 assert value >= 0
79 assert value < max
80 }
81}
82
83fn test_rand_i64n() {
84 max := i64(3246727724653636)
85 for _ in 0 .. rnd_count {
86 value := rand.i64n(max) or { panic("Couldn't obtain i64") }
87 assert value >= 0
88 assert value < max
89 }
90}
91
92fn test_rand_int_in_range() {
93 min := -4252
94 max := 23054962
95 for _ in 0 .. rnd_count {
96 value := rand.int_in_range(min, max) or { panic("Couldn't obtain int in range") }
97 assert value >= min
98 assert value < max
99 }
100}
101
102fn test_rand_i32_in_range() {
103 min := i32(-4252)
104 max := i32(23054962)
105 for _ in 0 .. rnd_count {
106 value := rand.i32_in_range(min, max) or { panic("Couldn't obtain i32 in range") }
107 assert value >= min
108 assert value < max
109 }
110}
111
112fn test_rand_i64_in_range() {
113 min := i64(-24095)
114 max := i64(324058)
115 for _ in 0 .. rnd_count {
116 value := rand.i64_in_range(min, max) or { panic("Couldn't obtain i64 in range") }
117 assert value >= min
118 assert value < max
119 }
120}
121
122fn test_rand_int31() {
123 max_u31 := int(0x7FFFFFFF)
124 sign_mask := int(u32(0x80000000))
125 for _ in 0 .. rnd_count {
126 value := rand.int31()
127 assert value >= 0
128 assert value <= max_u31
129 // This statement ensures that the sign bit is zero
130 assert (value & sign_mask) == 0
131 }
132}
133
134fn test_rand_int63() {
135 max_u63 := i64(0x7FFFFFFFFFFFFFFF)
136 sign_mask := i64(u64(0x8000000000000000))
137 for _ in 0 .. rnd_count {
138 value := rand.int63()
139 assert value >= 0
140 assert value <= max_u63
141 assert (value & sign_mask) == 0
142 }
143}
144
145fn test_rand_f32() {
146 for _ in 0 .. rnd_count {
147 value := rand.f32()
148 assert value >= 0.0
149 assert value < 1.0
150 }
151}
152
153fn test_rand_f64() {
154 for _ in 0 .. rnd_count {
155 value := rand.f64()
156 assert value >= 0.0
157 assert value < 1.0
158 }
159}
160
161fn test_rand_f32n() {
162 max := f32(357.0)
163 for _ in 0 .. rnd_count {
164 value := rand.f32n(max) or { panic("Couldn't obtain f32") }
165 assert value >= 0.0
166 assert value < max
167 }
168}
169
170fn test_rand_f64n() {
171 max := f64(1.52e6)
172 for _ in 0 .. rnd_count {
173 value := rand.f64n(max) or { panic("Couldn't obtain f64") }
174 assert value >= 0.0
175 assert value < max
176 }
177}
178
179fn test_rand_f32_in_range() {
180 min := f32(-24.0)
181 max := f32(125.0)
182 for _ in 0 .. rnd_count {
183 value := rand.f32_in_range(min, max) or { panic("Couldn't obtain f32 in range") }
184 assert value >= min
185 assert value < max
186 }
187}
188
189fn test_rand_f64_in_range() {
190 min := f64(-548.7)
191 max := f64(5015.2)
192 for _ in 0 .. rnd_count {
193 value := rand.f64_in_range(min, max) or { panic("Couldn't obtain f64 in range") }
194 assert value >= min
195 assert value < max
196 }
197}
198
199fn test_rand_u8() {
200 mut all := []u8{}
201 for _ in 0 .. 256 {
202 x := rand.u8()
203 assert x >= 0
204 assert x <= 255
205 all << x
206 }
207 all.sort(a < b)
208 assert all[0] != all[255]
209 assert all[0] != all[128]
210}
211
212fn test_rand_u16() {
213 mut all := []u16{}
214 mut same_as_previous := 0
215 mut previous := u16(0)
216 for _ in 0 .. 65536 {
217 x := rand.u16()
218 assert x >= 0
219 assert x <= 65535
220 all << x
221 if previous == x {
222 same_as_previous++
223 // dump(previous)
224 // dump(x)
225 }
226 previous = x
227 }
228 assert same_as_previous < 1000
229 all.sort(a < b)
230 assert all[0] != all[65535]
231 assert all[0] != all[32768]
232 // dump( all[0] )
233 // dump( all[65535] )
234 // dump( all[32768] )
235}
236
237const string_count = 25
238
239fn test_rand_string_from_set() {
240 sets := [
241 '0123456789',
242 'qwertyuiop',
243 'abcdefghijklmnopqrstuvwxyz',
244 ]
245 for charset in sets {
246 for _ in 0 .. string_count {
247 len := rand.intn(rnd_count) or { panic("Couldn't obtain int") }
248 str := rand.string_from_set(charset, len)
249 assert str.len == len
250 for character in str {
251 position := charset.index(character.ascii_str()) or { -1 }
252 assert position > -1
253 }
254 }
255 }
256}
257
258fn test_rand_fill_buffer_from_set() {
259 rand.seed([u32(0), 1])
260 outputs := [
261 [u8(50), 53, 57, 49, 53, 49, 56, 52, 57, 57],
262 [u8(55), 51, 52, 52, 50, 49, 53, 56, 52, 57],
263 [u8(56), 53, 52, 48, 52, 48, 57, 49, 50, 53],
264 [u8(52), 55, 53, 57, 54, 56, 49, 49, 49, 54],
265 [u8(50), 55, 50, 57, 50, 56, 57, 52, 52, 48],
266 [u8(49), 48, 48, 57, 57, 53, 49, 54, 50, 50],
267 [u8(49), 57, 50, 57, 51, 49, 49, 53, 54, 53],
268 [u8(56), 49, 52, 50, 56, 51, 48, 55, 54, 50],
269 [u8(50), 55, 54, 55, 48, 54, 50, 56, 51, 52],
270 [u8(51), 48, 50, 55, 54, 54, 49, 54, 54, 50],
271 [u8(50), 51, 51, 57, 50, 48, 56, 49, 54, 55],
272 [u8(51), 54, 51, 55, 56, 50, 54, 48, 51, 51],
273 ]
274 for output in outputs {
275 mut buf := []u8{len: 10}
276 rand.fill_buffer_from_set('0123456789', mut buf)
277 assert buf == output
278 }
279}
280
281fn test_rand_string() {
282 rand.seed([u32(0), 1])
283 outputs := [
284 'KNffDjUSbjLVyqkNLuklqtsEq',
285 'yHxahszRjWILjfqmLoTsIPCaS',
286 'JuuHjDLeuEjPMxhRzRUdOnegw',
287 'NOJeMKbelMQAgBijGqLgGXgcy',
288 'IRnHmuMXuddWLBsyeejpORynj',
289 'SNyWxnrFYoWyOSLnIxTzkxdlq',
290 'WzzZoOlnqzGKnUASSnlVqMtEg',
291 'CveNYBaLaEwguzgwLxilypSDD',
292 'XTBFsDOTHmTXcXjdmOqSAuAXz',
293 'MFoKXRXLQSeebMegDyUJyaHfu',
294 'EzaZjBJJWdGrASWqEPRRNQmgy',
295 'gZvLtGiyCYQSKxWBMEqVvTytn',
296 ]
297 for output in outputs {
298 assert rand.string(25) == output
299 }
300}
301
302fn test_rand_hex() {
303 rand.seed([u32(0), 1])
304 outputs := [
305 '035d15ec991bc42f502bcba28',
306 '49383ad7d8a51d44929ae9c04',
307 '30cdddd88e1963fb9367858e6',
308 '34f86c983ae6a38904dac56e8',
309 '6b1d08e94fb053688c1f47491',
310 '0700b91fea4808116b5deb7bc',
311 'c1dbac7941cc16ec81b70ef2a',
312 'c1cba301066e81a2df43cf051',
313 '51b7adc9dcd9695f004c686d1',
314 'a764df15e0009e02d02f88598',
315 '2d8393b743092c806537724a0',
316 '6b59704086e84f4b62cb11cb1',
317 'aebc14a5d7c2d447e6282f7ff',
318 '9ca8885813e42cb4380efeb84',
319 ]
320 for output in outputs {
321 assert rand.hex(25) == output
322 }
323}
324
325fn test_rand_ascii() {
326 rand.seed([u32(0), 1])
327 outputs := [
328 r'Yj6x`haolJh8UwGP.gq,Uj+\I',
329 r'5F@!@WF@tAulVN5-FqF;u"Y-9',
330 r'vo1xB>.MIu2lGj~f&$a4wNYeC',
331 r',M0o#M*QHa\myH{Bkkp#s&7/I',
332 r'abRN)Iq`)@b_*jKU_1x$Iv-ZF',
333 r'-@wQzJR0y+%{As"pqz.:Sz,L%',
334 r'1px~?MLh16UAVWO51>X~%3n7S',
335 r'Ed!vev=B-?OS)"W}N8gH5zU.R',
336 r'FR~8;&wB`!NFCRR,_IsIG{y|l',
337 ]
338 for output in outputs {
339 assert rand.ascii(25) == output
340 }
341}
342
343fn ensure_same_output(mut rng rand.PRNG) {
344 trng := rng.type_name()
345 println('> ensure a ${trng} instance works as a global generator, and produces the same output as a local one...')
346 for _ in 0 .. 100 {
347 assert rand.i8() == rng.i8()
348 assert rand.i16() == rng.i16()
349 assert rand.int() == rng.int()
350 assert rand.intn(45) or { 0 } == rng.intn(45) or { 0 }
351 assert rand.i32() == rng.i32()
352 assert rand.i32n(45) or { 0 } == rng.i32n(45) or { 0 }
353 assert rand.i64() == rng.i64()
354 assert rand.i64n(45) or { 0 } == rng.i64n(45) or { 0 }
355 //
356 assert rand.u8() == rng.u8()
357 assert rand.u16() == rng.u16()
358 assert rand.u32() == rng.u32()
359 assert rand.u32n(45) or { 0 } == rng.u32n(45) or { 0 }
360 assert rand.u64() == rng.u64()
361 assert rand.u64n(45) or { 0 } == rng.u64n(45) or { 0 }
362 //
363 assert rand.f32() == rng.f32()
364 assert rand.f32n(45) or { 0 } == rng.f32n(45) or { 0 }
365 assert rand.f64() == rng.f64()
366 assert rand.f64n(45) or { 0 } == rng.f64n(45) or { 0 }
367 }
368}
369
370fn test_new_global_rng() {
371 old := rand.get_current_rng()
372
373 // MuslRNG
374 mut rng1a := musl.MuslRNG{}
375 mut rng1b := musl.MuslRNG{}
376 seed1 := [u32(1234)]
377
378 rand.set_rng(rng1a)
379 rand.seed(seed1)
380 rng1b.seed(seed1)
381 ensure_same_output(mut rng1b)
382
383 // SplitMix64RNG
384 mut rng2a := splitmix64.SplitMix64RNG{}
385 mut rng2b := splitmix64.SplitMix64RNG{}
386 seed2 := [u32(2325), 14]
387
388 rand.set_rng(rng2a)
389 rand.seed(seed2)
390 rng2b.seed(seed2)
391 ensure_same_output(mut rng2b)
392
393 // MT19937RNG
394 mut rng3a := mt19937.MT19937RNG{}
395 mut rng3b := mt19937.MT19937RNG{}
396 seed3 := [u32(0xcafe), 234]
397
398 rand.set_rng(rng3a)
399 rand.seed(seed3)
400 rng3b.seed(seed3)
401 ensure_same_output(mut rng3b)
402
403 rand.set_rng(old)
404}
405
406fn test_shuffle() {
407 mut arrays := [][]int{}
408 arrays << [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
409 arrays << [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
410 for seed in seeds {
411 a := get_n_random_ints(seed, 10)
412 arrays << a
413 }
414 mut digits := []map[int]int{len: 10}
415 for digit in 0 .. 10 {
416 digits[digit] = {}
417 for idx in 0 .. 10 {
418 digits[digit][idx] = 0
419 }
420 }
421 for mut a in arrays {
422 o := a.clone()
423 for _ in 0 .. 100 {
424 rand.shuffle(mut a) or { panic('shuffle failed') }
425 assert *a != o
426 for idx in 0 .. 10 {
427 digits[idx][a[idx]]++
428 }
429 }
430 }
431 for digit in 1 .. 10 {
432 assert digits[0] != digits[digit]
433 }
434 for digit in 0 .. 10 {
435 for idx in 0 .. 10 {
436 assert digits[digit][idx] >= 10
437 }
438 // eprintln('digits[${digit}]: ${digits[digit]}')
439 }
440}
441
442fn test_shuffle_partial() {
443 mut a := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
444 mut b := a.clone()
445
446 rand.shuffle(mut a, start: 4)!
447 assert a[..4] == b[..4]
448
449 a = b.clone()
450 rand.shuffle(mut a, start: 3, end: 7)!
451 assert a[..3] == b[..3]
452 assert a[7..] == b[7..]
453}
454
455fn test_shuffle_clone() {
456 original := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
457 mut a := original.clone()
458 mut results := [][]int{}
459 for _ in 0 .. 10 {
460 results << rand.shuffle_clone(a) or { panic('shuffle failed') }
461 }
462 assert original == a
463 for idx in 1 .. 10 {
464 assert results[idx].len == 10
465 assert results[idx] != results[0]
466 assert results[idx] != original
467 }
468}
469
470fn test_choose() {
471 lengths := [1, 3, 4, 5, 6, 7]
472 a := ['one', 'two', 'three', 'four', 'five', 'six', 'seven']
473 for length in lengths {
474 b := rand.choose(a, length)!
475 assert b.len == length
476 for element in b {
477 assert element in a
478 // make sure every element occurs once
479 mut count := 0
480 for e in b {
481 if e == element {
482 count++
483 }
484 }
485 assert count == 1
486 }
487 }
488}
489
490fn test_sample() {
491 k := 20
492 a := ['heads', 'tails']
493 b := rand.sample(a, k)
494 assert b.len == k
495 for element in b {
496 assert element in a
497 }
498}
499
500fn test_element1() {
501 a := ['one', 'two', 'four', 'five', 'six', 'seven']
502 for _ in 0 .. 30 {
503 e := rand.element(a)!
504 assert e in a
505 assert 'three' != e
506 }
507}
508
509fn test_element2() {
510 for _ in 0 .. 30 {
511 e := rand.element([1, 2, 5, 6, 7, 8])!
512 assert e in [1, 2, 5, 6, 7, 8]
513 assert 3 != e
514 assert 4 != e
515 }
516}
517
518fn test_proper_masking() {
519 under32 := []int{len: 10, init: index * 0 + rand.intn(1073741823)!}
520 assert under32 != [0].repeat(10)
521
522 over32 := []int{len: 10, init: index * 0 + rand.intn(1073741824)!}
523 assert over32 != [0].repeat(10)
524
525 under64 := []i64{len: 10, init: index * 0 + rand.i64n(i64(4611686018427387903))!}
526 assert under64 != [i64(0)].repeat(10)
527
528 over64 := []i64{len: 10, init: index * 0 + rand.i64n(i64(4611686018427387904))!}
529 assert over64 != [i64(0)].repeat(10)
530
531 almost_full32 := []int{len: 10, init: index * 0 + rand.intn(2147483647)!}
532 assert almost_full32 != [0].repeat(10)
533
534 almost_full64 := []i64{len: 10, init: index * 0 + rand.i64n(i64(9223372036854775807))!}
535 assert almost_full64 != [i64(0)].repeat(10)
536}
537