v / vlib / rand / xoroshiro128pp / xoros128pp.v
105 lines · 94 sloc · 2.54 KB · 55e8faaedf64ec9e77581af873479891baf249d1
Raw
1// Copyright (c) 2022 John Lloyd. 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 xoroshiro128pp
5
6import rand.seed
7import rand.buffer
8
9pub const seed_len = 4 // u32, that is
10
11fn rotl(x u64, k int) u64 {
12 return (x << k) | (x >> (64 - k))
13}
14
15// XOROS128PPRNG is ported from https://prng.di.unimi.it/xoroshiro128plusplus.c .
16pub struct XOROS128PPRNG {
17 buffer.PRNGBuffer
18mut:
19 state0 u64 = u64(0x853c49e6748fea9b) ^ seed.time_seed_64()
20 state1 u64 = u64(0xda3e39cb94b95bdb) ^ seed.time_seed_64()
21}
22
23// seed seeds the XOROS128PPRNG with 4 `u32` values.
24pub fn (mut rng XOROS128PPRNG) seed(seed_data []u32) {
25 if seed_data.len != 4 {
26 eprintln('XOROS128PPRNG needs 4 u32s to be seeded.')
27 exit(1)
28 }
29 init_state0 := u64(seed_data[0]) | (u64(seed_data[1]) << 32)
30 init_state1 := u64(seed_data[2]) | (u64(seed_data[3]) << 32)
31 rng.state0 = init_state0
32 rng.state1 = init_state1
33 rng.u64()
34 rng.u64()
35 rng.bytes_left = 0
36 rng.buffer = 0
37}
38
39// byte returns a uniformly distributed pseudorandom 8-bit unsigned `byte`.
40@[inline]
41pub fn (mut rng XOROS128PPRNG) u8() u8 {
42 if rng.bytes_left >= 1 {
43 rng.bytes_left -= 1
44 value := u8(rng.buffer)
45 rng.buffer >>= 8
46 return value
47 }
48 ans := rng.u64()
49 rng.buffer = ans >> 8
50 rng.bytes_left = 7
51 return u8(ans)
52}
53
54// u16 returns a pseudorandom 16-bit unsigned integer (`u16`).
55@[inline]
56pub fn (mut rng XOROS128PPRNG) u16() u16 {
57 if rng.bytes_left >= 2 {
58 rng.bytes_left -= 2
59 value := u16(rng.buffer)
60 rng.buffer >>= 16
61 return value
62 }
63 ans := rng.u64()
64 rng.buffer = ans >> 16
65 rng.bytes_left = 6
66 return u16(ans)
67}
68
69// u32 returns a pseudorandom unsigned `u32`.
70@[inline]
71pub fn (mut rng XOROS128PPRNG) u32() u32 {
72 if rng.bytes_left >= 4 {
73 rng.bytes_left -= 4
74 value := u32(rng.buffer)
75 rng.buffer >>= 32
76 return value
77 }
78 ans := rng.u64()
79 rng.buffer = ans >> 32
80 rng.bytes_left = 4
81 return u32(ans)
82}
83
84// u64 returns a pseudorandom 64-bit unsigned `u64`.
85@[ignore_overflow; inline]
86pub fn (mut rng XOROS128PPRNG) u64() u64 {
87 oldstate0 := rng.state0
88 mut oldstate1 := rng.state1
89 res := rotl(oldstate0 + oldstate1, 17) + oldstate0
90 oldstate1 = oldstate1 ^ oldstate0
91 rng.state0 = rotl(oldstate0, 49) ^ oldstate1 ^ (oldstate1 << 21)
92 rng.state1 = rotl(oldstate1, 28)
93 return res
94}
95
96// block_size returns the number of bits that the RNG can produce in a single iteration.
97@[inline]
98pub fn (mut rng XOROS128PPRNG) block_size() int {
99 return 64
100}
101
102// free should be called when the generator is no longer needed.
103@[unsafe]
104pub fn (mut rng XOROS128PPRNG) free() {
105}
106