rand: separate rand.util and rand.seed submodules (#8353)

pull/8357/head
Subhomoy Haldar 2021-01-26 19:25:09 +05:30 committed by GitHub
parent 5f2b2df546
commit 97103f680a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 107 additions and 104 deletions

View File

@ -3,7 +3,7 @@ module util
import os
import rand
import rand.wyrand
import rand.util as rutil
import rand.seed as rseed
const (
retries = 10000
@ -26,9 +26,7 @@ pub fn temp_file(tfo TempFileOptions) ?(os.File, string) {
}
d = d.trim_right(os.path_separator)
mut rng := rand.new_default(rand.PRNGConfigStruct{})
prefix, suffix := prefix_and_suffix(tfo.pattern) or {
return error(@FN + ' ' + err)
}
prefix, suffix := prefix_and_suffix(tfo.pattern) or { return error(@FN + ' ' + err) }
for retry := 0; retry < retries; retry++ {
path := os.join_path(d, prefix + random_number(mut rng) + suffix)
mut mode := 'rw+'
@ -36,7 +34,7 @@ pub fn temp_file(tfo TempFileOptions) ?(os.File, string) {
mode = 'w+'
}
mut file := os.open_file(path, mode, 0o600) or {
rng.seed(rutil.time_seed_array(2))
rng.seed(rseed.time_seed_array(2))
continue
}
if os.exists(path) && os.is_file(path) {
@ -64,13 +62,11 @@ pub fn temp_dir(tdo TempFileOptions) ?string {
}
d = d.trim_right(os.path_separator)
mut rng := rand.new_default(rand.PRNGConfigStruct{})
prefix, suffix := prefix_and_suffix(tdo.pattern) or {
return error(@FN + ' ' + err)
}
prefix, suffix := prefix_and_suffix(tdo.pattern) or { return error(@FN + ' ' + err) }
for retry := 0; retry < retries; retry++ {
path := os.join_path(d, prefix + random_number(mut rng) + suffix)
os.mkdir_all(path) or {
rng.seed(rutil.time_seed_array(2))
rng.seed(rseed.time_seed_array(2))
continue
}
if os.is_dir(path) && os.exists(path) {
@ -96,9 +92,7 @@ fn prefix_and_suffix(pattern string) ?(string, string) {
if pat.contains(os.path_separator) {
return error('pattern cannot contain path separators ($os.path_separator).')
}
pos := pat.last_index('*') or {
-1
}
pos := pat.last_index('*') or { -1 }
mut prefix := ''
mut suffix := ''
if pos != -1 {

View File

@ -4,7 +4,7 @@
module mt19937
import math.bits
import rand.util
import rand.seed
/*
C++ functions for MT19937, with initialization improved 2002/2/10.
@ -59,8 +59,8 @@ const (
// MT19937RNG is generator that uses the Mersenne Twister algorithm with period 2^19937.
pub struct MT19937RNG {
mut:
state []u64 = calculate_state(util.time_seed_array(2), mut []u64{len: nn})
mti int = nn
state []u64 = calculate_state(seed.time_seed_array(2), mut []u64{len: mt19937.nn})
mti int = mt19937.nn
next_rnd u32
has_next bool
}
@ -70,7 +70,7 @@ fn calculate_state(seed_data []u32, mut state []u64) []u64 {
lo := u64(seed_data[0])
hi := u64(seed_data[1])
state[0] = u64((hi << 32) | lo)
for j := 1; j < nn; j++ {
for j := 1; j < mt19937.nn; j++ {
state[j] = u64(6364136223846793005) * (state[j - 1] ^ (state[j - 1] >> 62)) + u64(j)
}
return *state
@ -84,7 +84,7 @@ pub fn (mut rng MT19937RNG) seed(seed_data []u32) {
exit(1)
}
rng.state = calculate_state(seed_data, mut rng.state)
rng.mti = nn
rng.mti = mt19937.nn
rng.next_rnd = 0
rng.has_next = false
}
@ -105,21 +105,21 @@ pub fn (mut rng MT19937RNG) u32() u32 {
// u64 returns a pseudorandom 64bit int in range `[0, 2⁶⁴)`.
[inline]
pub fn (mut rng MT19937RNG) u64() u64 {
mag01 := [u64(0), u64(matrix_a)]
mag01 := [u64(0), u64(mt19937.matrix_a)]
mut x := u64(0)
mut i := int(0)
if rng.mti >= nn {
for i = 0; i < nn - mm; i++ {
x = (rng.state[i] & um) | (rng.state[i + 1] & lm)
rng.state[i] = rng.state[i + mm] ^ (x >> 1) ^ mag01[int(x & 1)]
if rng.mti >= mt19937.nn {
for i = 0; i < mt19937.nn - mt19937.mm; i++ {
x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm)
rng.state[i] = rng.state[i + mt19937.mm] ^ (x >> 1) ^ mag01[int(x & 1)]
}
for i < nn - 1 {
x = (rng.state[i] & um) | (rng.state[i + 1] & lm)
rng.state[i] = rng.state[i + (mm - nn)] ^ (x >> 1) ^ mag01[int(x & 1)]
for i < mt19937.nn - 1 {
x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm)
rng.state[i] = rng.state[i + (mt19937.mm - mt19937.nn)] ^ (x >> 1) ^ mag01[int(x & 1)]
i++
}
x = (rng.state[nn - 1] & um) | (rng.state[0] & lm)
rng.state[nn - 1] = rng.state[mm - 1] ^ (x >> 1) ^ mag01[int(x & 1)]
x = (rng.state[mt19937.nn - 1] & mt19937.um) | (rng.state[0] & mt19937.lm)
rng.state[mt19937.nn - 1] = rng.state[mt19937.mm - 1] ^ (x >> 1) ^ mag01[int(x & 1)]
rng.mti = 0
}
x = rng.state[rng.mti]
@ -279,7 +279,7 @@ pub fn (mut rng MT19937RNG) f32() f32 {
// f64 returns 64bit real (`f64`) in range `[0, 1)`.
[inline]
pub fn (mut rng MT19937RNG) f64() f64 {
return f64(rng.u64() >> 11) * inv_f64_limit
return f64(rng.u64() >> 11) * mt19937.inv_f64_limit
}
// f32n returns a 32bit real (`f32`) in range [0, max)`.

View File

@ -1,6 +1,6 @@
import math
import rand.mt19937
import rand.util
import rand.seed
const (
range_limit = 40
@ -26,7 +26,7 @@ fn mt19937_basic_test() {
fn gen_randoms(seed_data []u32, bound int) []u64 {
bound_u64 := u64(bound)
mut randoms := []u64{len:(20)}
mut randoms := []u64{len: (20)}
mut rnd := mt19937.MT19937RNG{}
rnd.seed(seed_data)
for i in 0 .. 20 {
@ -36,7 +36,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
}
fn test_mt19937_reproducibility() {
seed_data := util.time_seed_array(2)
seed_data := seed.time_seed_array(2)
randoms1 := gen_randoms(seed_data, 1000)
randoms2 := gen_randoms(seed_data, 1000)
assert randoms1.len == randoms2.len

View File

@ -4,12 +4,13 @@
module musl
import math.bits
import rand.seed
import rand.util
// MuslRNG ported from https://git.musl-libc.org/cgit/musl/tree/src/prng/rand_r.c
pub struct MuslRNG {
mut:
state u32 = util.time_seed_32()
state u32 = seed.time_seed_32()
}
// seed sets the current random state based on `seed_data`.

View File

@ -1,6 +1,6 @@
import math
import rand.musl
import rand.util
import rand.seed
const (
range_limit = 40
@ -16,7 +16,7 @@ const (
fn gen_randoms(seed_data []u32, bound int) []u64 {
bound_u64 := u64(bound)
mut randoms := []u64{len:(20)}
mut randoms := []u64{len: (20)}
mut rnd := musl.MuslRNG{}
rnd.seed(seed_data)
for i in 0 .. 20 {
@ -26,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
}
fn test_musl_reproducibility() {
seed_data := util.time_seed_array(1)
seed_data := seed.time_seed_array(1)
randoms1 := gen_randoms(seed_data, 1000)
randoms2 := gen_randoms(seed_data, 1000)
assert randoms1.len == randoms2.len

View File

@ -3,6 +3,7 @@
// that can be found in the LICENSE file.
module pcg32
import rand.seed
import rand.util
// PCG32RNG ported from http://www.pcg-random.org/download.html,
@ -10,8 +11,8 @@ import rand.util
// https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.h
pub struct PCG32RNG {
mut:
state u64 = u64(0x853c49e6748fea9b) ^ util.time_seed_64()
inc u64 = u64(0xda3e39cb94b95bdb) ^ util.time_seed_64()
state u64 = u64(0x853c49e6748fea9b) ^ seed.time_seed_64()
inc u64 = u64(0xda3e39cb94b95bdb) ^ seed.time_seed_64()
}
// seed seeds the PCG32RNG with 4 `u32` values.

View File

@ -1,6 +1,6 @@
import math
import rand.pcg32
import rand.util
import rand.seed
const (
range_limit = 40
@ -25,7 +25,7 @@ fn gen_randoms(seed_data []u32, bound int) []u32 {
}
fn test_pcg32_reproducibility() {
seed_data := util.time_seed_array(4)
seed_data := seed.time_seed_array(4)
randoms1 := gen_randoms(seed_data, 1000)
randoms2 := gen_randoms(seed_data, 1000)
assert randoms1.len == randoms2.len

View File

@ -3,13 +3,13 @@
// that can be found in the LICENSE file.
module rand
import rand.util
import rand.seed
import rand.wyrand
import time
// PRNGConfigStruct is a configuration struct for creating a new instance of the default RNG.
pub struct PRNGConfigStruct {
seed []u32 = util.time_seed_array(2)
seed []u32 = seed.time_seed_array(2)
}
__global ( default_rng &wyrand.WyRandRNG )
@ -141,10 +141,10 @@ pub fn string(len int) string {
mut buf := malloc(len)
for i in 0 .. len {
unsafe {
buf[i] = chars[intn(chars.len)]
buf[i] = rand.chars[intn(rand.chars.len)]
}
}
return unsafe {buf.vstring_with_len(len)}
return unsafe { buf.vstring_with_len(len) }
}
// uuid_v4 generates a random (v4) UUID
@ -184,7 +184,7 @@ pub fn uuid_v4() string {
buf[14] = `4`
buf[buflen] = 0
}
return unsafe {buf.vstring_with_len(buflen)}
return unsafe { buf.vstring_with_len(buflen) }
}
const (
@ -209,7 +209,7 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
mut i := 9
for i >= 0 {
unsafe {
buf[i] = ulid_encoding[t & 0x1F]
buf[i] = rand.ulid_encoding[t & 0x1F]
}
t = t >> 5
i--
@ -219,7 +219,7 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
i = 10
for i < 19 {
unsafe {
buf[i] = ulid_encoding[x & 0x1F]
buf[i] = rand.ulid_encoding[x & 0x1F]
}
x = x >> 5
i++
@ -228,7 +228,7 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
x = default_rng.u64()
for i < 26 {
unsafe {
buf[i] = ulid_encoding[x & 0x1F]
buf[i] = rand.ulid_encoding[x & 0x1F]
}
x = x >> 5
i++
@ -236,5 +236,5 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
unsafe {
buf[26] = 0
}
return unsafe {buf.vstring_with_len(buflen)}
return unsafe { buf.vstring_with_len(buflen) }
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module seed
import time
// nr_next returns a next value based on the previous value `prev`.
[inline]
fn nr_next(prev u32) u32 {
return prev * 1664525 + 1013904223
}
// time_seed_array returns the required number of u32s generated from system time.
[inline]
pub fn time_seed_array(count int) []u32 {
ctime := time.now()
mut seed := u32(ctime.unix_time() ^ ctime.microsecond)
mut seed_data := []u32{cap: count}
for _ in 0 .. count {
seed = nr_next(seed)
seed_data << nr_next(seed)
}
return seed_data
}
// time_seed_32 returns a 32-bit seed generated from system time.
[inline]
pub fn time_seed_32() u32 {
return time_seed_array(1)[0]
}
// time_seed_64 returns a 64-bit seed generated from system time.
[inline]
pub fn time_seed_64() u64 {
seed_data := time_seed_array(2)
lower := u64(seed_data[0])
upper := u64(seed_data[1])
return lower | (upper << 32)
}

View File

@ -3,12 +3,13 @@
// that can be found in the LICENSE file.
module splitmix64
import rand.seed
import rand.util
// SplitMix64RNG ported from http://xoshiro.di.unimi.it/splitmix64.c
pub struct SplitMix64RNG {
mut:
state u64 = util.time_seed_64()
state u64 = seed.time_seed_64()
has_extra bool
extra u32
}

View File

@ -1,6 +1,6 @@
import math
import rand.splitmix64
import rand.util
import rand.seed
const (
range_limit = 40
@ -16,7 +16,7 @@ const (
fn gen_randoms(seed_data []u32, bound int) []u64 {
bound_u64 := u64(bound)
mut randoms := []u64{len:(20)}
mut randoms := []u64{len: (20)}
mut rnd := splitmix64.SplitMix64RNG{}
rnd.seed(seed_data)
for i in 0 .. 20 {
@ -26,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
}
fn test_splitmix64_reproducibility() {
seed_data := util.time_seed_array(2)
seed_data := seed.time_seed_array(2)
randoms1 := gen_randoms(seed_data, 1000)
randoms2 := gen_randoms(seed_data, 1000)
assert randoms1.len == randoms2.len

View File

@ -4,6 +4,7 @@
module sys
import math.bits
import rand.seed
import rand.util
// Implementation note:
@ -23,8 +24,8 @@ const (
)
fn calculate_iterations_for(bits int) int {
base := bits / rand_bitsize
extra := if bits % rand_bitsize == 0 { 0 } else { 1 }
base := bits / sys.rand_bitsize
extra := if bits % sys.rand_bitsize == 0 { 0 } else { 1 }
return base + extra
}
@ -36,7 +37,7 @@ fn C.rand() int
// SysRNG is the PRNG provided by default in the libc implementiation that V uses.
pub struct SysRNG {
mut:
seed u32 = util.time_seed_32()
seed u32 = seed.time_seed_32()
}
// r.seed() sets the seed of the accepting SysRNG to the given data.
@ -46,7 +47,7 @@ pub fn (mut r SysRNG) seed(seed_data []u32) {
exit(1)
}
r.seed = seed_data[0]
unsafe {C.srand(int(r.seed))}
unsafe { C.srand(int(r.seed)) }
}
// r.default_rand() exposes the default behavior of the system's RNG
@ -63,8 +64,8 @@ pub fn (r SysRNG) default_rand() int {
[inline]
pub fn (r SysRNG) u32() u32 {
mut result := u32(C.rand())
for i in 1 .. u32_iter_count {
result = result ^ (u32(C.rand()) << (rand_bitsize * i))
for i in 1 .. sys.u32_iter_count {
result = result ^ (u32(C.rand()) << (sys.rand_bitsize * i))
}
return result
}
@ -73,8 +74,8 @@ pub fn (r SysRNG) u32() u32 {
[inline]
pub fn (r SysRNG) u64() u64 {
mut result := u64(C.rand())
for i in 1 .. u64_iter_count {
result = result ^ (u64(C.rand()) << (rand_bitsize * i))
for i in 1 .. sys.u64_iter_count {
result = result ^ (u64(C.rand()) << (sys.rand_bitsize * i))
}
return result
}

View File

@ -3,8 +3,6 @@
// that can be found in the LICENSE file.
module util
import time
// Commonly used constants across RNGs - some taken from "Numerical Recipes".
pub const (
lower_mask = u64(0x00000000FFFFFFFF)
@ -15,37 +13,3 @@ pub const (
u31_mask = u32(0x7FFFFFFF)
u63_mask = u64(0x7FFFFFFFFFFFFFFF)
)
// nr_next returns a next value based on the previous value `prev`.
[inline]
fn nr_next(prev u32) u32 {
return prev * 1664525 + 1013904223
}
// time_seed_array returns the required number of u32s generated from system time.
[inline]
pub fn time_seed_array(count int) []u32 {
ctime := time.now()
mut seed := u32(ctime.unix_time() ^ ctime.microsecond)
mut seed_data := []u32{cap: count}
for _ in 0 .. count {
seed = nr_next(seed)
seed_data << nr_next(seed)
}
return seed_data
}
// time_seed_32 returns a 32-bit seed generated from system time.
[inline]
pub fn time_seed_32() u32 {
return time_seed_array(1)[0]
}
// time_seed_64 returns a 64-bit seed generated from system time.
[inline]
pub fn time_seed_64() u64 {
seed_data := time_seed_array(2)
lower := u64(seed_data[0])
upper := u64(seed_data[1])
return lower | (upper << 32)
}

View File

@ -4,8 +4,9 @@
module wyrand
import math.bits
import rand.seed
import rand.util
import hash as wyhash
import hash
// Redefinition of some constants that we will need for pseudorandom number generation.
const (
@ -16,7 +17,7 @@ const (
// WyRandRNG is a RNG based on the WyHash hashing algorithm.
pub struct WyRandRNG {
mut:
state u64 = util.time_seed_64()
state u64 = seed.time_seed_64()
has_extra bool
extra u32
}
@ -51,9 +52,9 @@ pub fn (mut rng WyRandRNG) u32() u32 {
pub fn (mut rng WyRandRNG) u64() u64 {
unsafe {
mut seed1 := rng.state
seed1 += wyp0
seed1 += wyrand.wyp0
rng.state = seed1
return wyhash.wymum(seed1 ^ wyp1, seed1)
return hash.wymum(seed1 ^ wyrand.wyp1, seed1)
}
return 0
}

View File

@ -1,5 +1,5 @@
import math
import rand.util
import rand.seed
import rand.wyrand
const (
@ -16,7 +16,7 @@ const (
fn gen_randoms(seed_data []u32, bound int) []u64 {
bound_u64 := u64(bound)
mut randoms := []u64{len:(20)}
mut randoms := []u64{len: (20)}
mut rnd := wyrand.WyRandRNG{}
rnd.seed(seed_data)
for i in 0 .. 20 {
@ -26,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
}
fn test_wyrand_reproducibility() {
seed_data := util.time_seed_array(2)
seed_data := seed.time_seed_array(2)
randoms1 := gen_randoms(seed_data, 1000)
randoms2 := gen_randoms(seed_data, 1000)
assert randoms1.len == randoms2.len