v / vlib / rand / wyrand / wyrand.v
87 lines · 78 sloc · 2.08 KB · f21cce4b6929222724c3b1097242850c58712620
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module wyrand
5
6import rand.buffer
7import rand.seed
8
9// Redefinition of some constants that we will need for pseudorandom number generation.
10const wyp0 = u64(0x2d358dccaa6c78a5)
11const wyp1 = u64(0x8bb84b93962eacc9)
12
13pub const seed_len = 2
14
15// WyRandRNG is a RNG based on the WyHash hashing algorithm.
16pub struct WyRandRNG {
17 buffer.PRNGBuffer
18mut:
19 state u64 = seed.time_seed_64()
20 bytes_left int
21 buffer u64
22}
23
24// seed sets the seed, needs only two `u32`s in little-endian format as [lower, higher].
25pub fn (mut rng WyRandRNG) seed(seed_data []u32) {
26 if seed_data.len != 2 {
27 eprintln('WyRandRNG needs 2 32-bit unsigned integers as the seed.')
28 exit(1)
29 }
30 rng.state = seed_data[0] | (u64(seed_data[1]) << 32)
31 rng.bytes_left = 0
32 rng.buffer = 0
33}
34
35// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
36@[inline]
37pub fn (mut rng WyRandRNG) u8() u8 {
38 // Can we extract a value from the buffer?
39 if rng.bytes_left >= 1 {
40 rng.bytes_left -= 1
41 value := u8(rng.buffer)
42 rng.buffer >>= 8
43 return value
44 }
45 // Add a new value to the buffer
46 rng.buffer = rng.u64()
47 rng.bytes_left = 7
48 value := u8(rng.buffer)
49 rng.buffer >>= 8
50 return value
51}
52
53// u16 returns a pseudorandom 16bit int in range `[0, 2¹⁶)`.
54@[inline]
55pub fn (mut rng WyRandRNG) u16() u16 {
56 if rng.bytes_left >= 2 {
57 rng.bytes_left -= 2
58 value := u16(rng.buffer)
59 rng.buffer >>= 16
60 return value
61 }
62 ans := rng.u64()
63 rng.buffer = ans >> 16
64 rng.bytes_left = 6
65 return u16(ans)
66}
67
68// u32 returns a pseudorandom 32bit int in range `[0, 2³²)`.
69@[inline]
70pub fn (mut rng WyRandRNG) u32() u32 {
71 if rng.bytes_left >= 4 {
72 rng.bytes_left -= 4
73 value := u32(rng.buffer)
74 rng.buffer >>= 32
75 return value
76 }
77 ans := rng.u64()
78 rng.buffer = ans >> 32
79 rng.bytes_left = 4
80 return u32(ans)
81}
82
83// block_size returns the number of bits that the RNG can produce in a single iteration.
84@[inline]
85pub fn (mut rng WyRandRNG) block_size() int {
86 return 64
87}
88