rand: separate rand.util and rand.seed submodules (#8353)
parent
5f2b2df546
commit
97103f680a
|
@ -3,7 +3,7 @@ module util
|
||||||
import os
|
import os
|
||||||
import rand
|
import rand
|
||||||
import rand.wyrand
|
import rand.wyrand
|
||||||
import rand.util as rutil
|
import rand.seed as rseed
|
||||||
|
|
||||||
const (
|
const (
|
||||||
retries = 10000
|
retries = 10000
|
||||||
|
@ -26,9 +26,7 @@ pub fn temp_file(tfo TempFileOptions) ?(os.File, string) {
|
||||||
}
|
}
|
||||||
d = d.trim_right(os.path_separator)
|
d = d.trim_right(os.path_separator)
|
||||||
mut rng := rand.new_default(rand.PRNGConfigStruct{})
|
mut rng := rand.new_default(rand.PRNGConfigStruct{})
|
||||||
prefix, suffix := prefix_and_suffix(tfo.pattern) or {
|
prefix, suffix := prefix_and_suffix(tfo.pattern) or { return error(@FN + ' ' + err) }
|
||||||
return error(@FN + ' ' + err)
|
|
||||||
}
|
|
||||||
for retry := 0; retry < retries; retry++ {
|
for retry := 0; retry < retries; retry++ {
|
||||||
path := os.join_path(d, prefix + random_number(mut rng) + suffix)
|
path := os.join_path(d, prefix + random_number(mut rng) + suffix)
|
||||||
mut mode := 'rw+'
|
mut mode := 'rw+'
|
||||||
|
@ -36,7 +34,7 @@ pub fn temp_file(tfo TempFileOptions) ?(os.File, string) {
|
||||||
mode = 'w+'
|
mode = 'w+'
|
||||||
}
|
}
|
||||||
mut file := os.open_file(path, mode, 0o600) or {
|
mut file := os.open_file(path, mode, 0o600) or {
|
||||||
rng.seed(rutil.time_seed_array(2))
|
rng.seed(rseed.time_seed_array(2))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if os.exists(path) && os.is_file(path) {
|
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)
|
d = d.trim_right(os.path_separator)
|
||||||
mut rng := rand.new_default(rand.PRNGConfigStruct{})
|
mut rng := rand.new_default(rand.PRNGConfigStruct{})
|
||||||
prefix, suffix := prefix_and_suffix(tdo.pattern) or {
|
prefix, suffix := prefix_and_suffix(tdo.pattern) or { return error(@FN + ' ' + err) }
|
||||||
return error(@FN + ' ' + err)
|
|
||||||
}
|
|
||||||
for retry := 0; retry < retries; retry++ {
|
for retry := 0; retry < retries; retry++ {
|
||||||
path := os.join_path(d, prefix + random_number(mut rng) + suffix)
|
path := os.join_path(d, prefix + random_number(mut rng) + suffix)
|
||||||
os.mkdir_all(path) or {
|
os.mkdir_all(path) or {
|
||||||
rng.seed(rutil.time_seed_array(2))
|
rng.seed(rseed.time_seed_array(2))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if os.is_dir(path) && os.exists(path) {
|
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) {
|
if pat.contains(os.path_separator) {
|
||||||
return error('pattern cannot contain path separators ($os.path_separator).')
|
return error('pattern cannot contain path separators ($os.path_separator).')
|
||||||
}
|
}
|
||||||
pos := pat.last_index('*') or {
|
pos := pat.last_index('*') or { -1 }
|
||||||
-1
|
|
||||||
}
|
|
||||||
mut prefix := ''
|
mut prefix := ''
|
||||||
mut suffix := ''
|
mut suffix := ''
|
||||||
if pos != -1 {
|
if pos != -1 {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
module mt19937
|
module mt19937
|
||||||
|
|
||||||
import math.bits
|
import math.bits
|
||||||
import rand.util
|
import rand.seed
|
||||||
|
|
||||||
/*
|
/*
|
||||||
C++ functions for MT19937, with initialization improved 2002/2/10.
|
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.
|
// MT19937RNG is generator that uses the Mersenne Twister algorithm with period 2^19937.
|
||||||
pub struct MT19937RNG {
|
pub struct MT19937RNG {
|
||||||
mut:
|
mut:
|
||||||
state []u64 = calculate_state(util.time_seed_array(2), mut []u64{len: nn})
|
state []u64 = calculate_state(seed.time_seed_array(2), mut []u64{len: mt19937.nn})
|
||||||
mti int = nn
|
mti int = mt19937.nn
|
||||||
next_rnd u32
|
next_rnd u32
|
||||||
has_next bool
|
has_next bool
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ fn calculate_state(seed_data []u32, mut state []u64) []u64 {
|
||||||
lo := u64(seed_data[0])
|
lo := u64(seed_data[0])
|
||||||
hi := u64(seed_data[1])
|
hi := u64(seed_data[1])
|
||||||
state[0] = u64((hi << 32) | lo)
|
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)
|
state[j] = u64(6364136223846793005) * (state[j - 1] ^ (state[j - 1] >> 62)) + u64(j)
|
||||||
}
|
}
|
||||||
return *state
|
return *state
|
||||||
|
@ -84,7 +84,7 @@ pub fn (mut rng MT19937RNG) seed(seed_data []u32) {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
rng.state = calculate_state(seed_data, mut rng.state)
|
rng.state = calculate_state(seed_data, mut rng.state)
|
||||||
rng.mti = nn
|
rng.mti = mt19937.nn
|
||||||
rng.next_rnd = 0
|
rng.next_rnd = 0
|
||||||
rng.has_next = false
|
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⁶⁴)`.
|
// u64 returns a pseudorandom 64bit int in range `[0, 2⁶⁴)`.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut rng MT19937RNG) u64() u64 {
|
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 x := u64(0)
|
||||||
mut i := int(0)
|
mut i := int(0)
|
||||||
if rng.mti >= nn {
|
if rng.mti >= mt19937.nn {
|
||||||
for i = 0; i < nn - mm; i++ {
|
for i = 0; i < mt19937.nn - mt19937.mm; i++ {
|
||||||
x = (rng.state[i] & um) | (rng.state[i + 1] & lm)
|
x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm)
|
||||||
rng.state[i] = rng.state[i + mm] ^ (x >> 1) ^ mag01[int(x & 1)]
|
rng.state[i] = rng.state[i + mt19937.mm] ^ (x >> 1) ^ mag01[int(x & 1)]
|
||||||
}
|
}
|
||||||
for i < nn - 1 {
|
for i < mt19937.nn - 1 {
|
||||||
x = (rng.state[i] & um) | (rng.state[i + 1] & lm)
|
x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm)
|
||||||
rng.state[i] = rng.state[i + (mm - nn)] ^ (x >> 1) ^ mag01[int(x & 1)]
|
rng.state[i] = rng.state[i + (mt19937.mm - mt19937.nn)] ^ (x >> 1) ^ mag01[int(x & 1)]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
x = (rng.state[nn - 1] & um) | (rng.state[0] & lm)
|
x = (rng.state[mt19937.nn - 1] & mt19937.um) | (rng.state[0] & mt19937.lm)
|
||||||
rng.state[nn - 1] = rng.state[mm - 1] ^ (x >> 1) ^ mag01[int(x & 1)]
|
rng.state[mt19937.nn - 1] = rng.state[mt19937.mm - 1] ^ (x >> 1) ^ mag01[int(x & 1)]
|
||||||
rng.mti = 0
|
rng.mti = 0
|
||||||
}
|
}
|
||||||
x = rng.state[rng.mti]
|
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)`.
|
// f64 returns 64bit real (`f64`) in range `[0, 1)`.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut rng MT19937RNG) f64() f64 {
|
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)`.
|
// f32n returns a 32bit real (`f32`) in range [0, max)`.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import math
|
import math
|
||||||
import rand.mt19937
|
import rand.mt19937
|
||||||
import rand.util
|
import rand.seed
|
||||||
|
|
||||||
const (
|
const (
|
||||||
range_limit = 40
|
range_limit = 40
|
||||||
|
@ -26,7 +26,7 @@ fn mt19937_basic_test() {
|
||||||
|
|
||||||
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
bound_u64 := u64(bound)
|
bound_u64 := u64(bound)
|
||||||
mut randoms := []u64{len:(20)}
|
mut randoms := []u64{len: (20)}
|
||||||
mut rnd := mt19937.MT19937RNG{}
|
mut rnd := mt19937.MT19937RNG{}
|
||||||
rnd.seed(seed_data)
|
rnd.seed(seed_data)
|
||||||
for i in 0 .. 20 {
|
for i in 0 .. 20 {
|
||||||
|
@ -36,7 +36,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_mt19937_reproducibility() {
|
fn test_mt19937_reproducibility() {
|
||||||
seed_data := util.time_seed_array(2)
|
seed_data := seed.time_seed_array(2)
|
||||||
randoms1 := gen_randoms(seed_data, 1000)
|
randoms1 := gen_randoms(seed_data, 1000)
|
||||||
randoms2 := gen_randoms(seed_data, 1000)
|
randoms2 := gen_randoms(seed_data, 1000)
|
||||||
assert randoms1.len == randoms2.len
|
assert randoms1.len == randoms2.len
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
module musl
|
module musl
|
||||||
|
|
||||||
import math.bits
|
import math.bits
|
||||||
|
import rand.seed
|
||||||
import rand.util
|
import rand.util
|
||||||
|
|
||||||
// MuslRNG ported from https://git.musl-libc.org/cgit/musl/tree/src/prng/rand_r.c
|
// MuslRNG ported from https://git.musl-libc.org/cgit/musl/tree/src/prng/rand_r.c
|
||||||
pub struct MuslRNG {
|
pub struct MuslRNG {
|
||||||
mut:
|
mut:
|
||||||
state u32 = util.time_seed_32()
|
state u32 = seed.time_seed_32()
|
||||||
}
|
}
|
||||||
|
|
||||||
// seed sets the current random state based on `seed_data`.
|
// seed sets the current random state based on `seed_data`.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import math
|
import math
|
||||||
import rand.musl
|
import rand.musl
|
||||||
import rand.util
|
import rand.seed
|
||||||
|
|
||||||
const (
|
const (
|
||||||
range_limit = 40
|
range_limit = 40
|
||||||
|
@ -16,7 +16,7 @@ const (
|
||||||
|
|
||||||
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
bound_u64 := u64(bound)
|
bound_u64 := u64(bound)
|
||||||
mut randoms := []u64{len:(20)}
|
mut randoms := []u64{len: (20)}
|
||||||
mut rnd := musl.MuslRNG{}
|
mut rnd := musl.MuslRNG{}
|
||||||
rnd.seed(seed_data)
|
rnd.seed(seed_data)
|
||||||
for i in 0 .. 20 {
|
for i in 0 .. 20 {
|
||||||
|
@ -26,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_musl_reproducibility() {
|
fn test_musl_reproducibility() {
|
||||||
seed_data := util.time_seed_array(1)
|
seed_data := seed.time_seed_array(1)
|
||||||
randoms1 := gen_randoms(seed_data, 1000)
|
randoms1 := gen_randoms(seed_data, 1000)
|
||||||
randoms2 := gen_randoms(seed_data, 1000)
|
randoms2 := gen_randoms(seed_data, 1000)
|
||||||
assert randoms1.len == randoms2.len
|
assert randoms1.len == randoms2.len
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module pcg32
|
module pcg32
|
||||||
|
|
||||||
|
import rand.seed
|
||||||
import rand.util
|
import rand.util
|
||||||
|
|
||||||
// PCG32RNG ported from http://www.pcg-random.org/download.html,
|
// 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
|
// https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.h
|
||||||
pub struct PCG32RNG {
|
pub struct PCG32RNG {
|
||||||
mut:
|
mut:
|
||||||
state u64 = u64(0x853c49e6748fea9b) ^ util.time_seed_64()
|
state u64 = u64(0x853c49e6748fea9b) ^ seed.time_seed_64()
|
||||||
inc u64 = u64(0xda3e39cb94b95bdb) ^ util.time_seed_64()
|
inc u64 = u64(0xda3e39cb94b95bdb) ^ seed.time_seed_64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// seed seeds the PCG32RNG with 4 `u32` values.
|
// seed seeds the PCG32RNG with 4 `u32` values.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import math
|
import math
|
||||||
import rand.pcg32
|
import rand.pcg32
|
||||||
import rand.util
|
import rand.seed
|
||||||
|
|
||||||
const (
|
const (
|
||||||
range_limit = 40
|
range_limit = 40
|
||||||
|
@ -25,7 +25,7 @@ fn gen_randoms(seed_data []u32, bound int) []u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_pcg32_reproducibility() {
|
fn test_pcg32_reproducibility() {
|
||||||
seed_data := util.time_seed_array(4)
|
seed_data := seed.time_seed_array(4)
|
||||||
randoms1 := gen_randoms(seed_data, 1000)
|
randoms1 := gen_randoms(seed_data, 1000)
|
||||||
randoms2 := gen_randoms(seed_data, 1000)
|
randoms2 := gen_randoms(seed_data, 1000)
|
||||||
assert randoms1.len == randoms2.len
|
assert randoms1.len == randoms2.len
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module rand
|
module rand
|
||||||
|
|
||||||
import rand.util
|
import rand.seed
|
||||||
import rand.wyrand
|
import rand.wyrand
|
||||||
import time
|
import time
|
||||||
|
|
||||||
// PRNGConfigStruct is a configuration struct for creating a new instance of the default RNG.
|
// PRNGConfigStruct is a configuration struct for creating a new instance of the default RNG.
|
||||||
pub struct PRNGConfigStruct {
|
pub struct PRNGConfigStruct {
|
||||||
seed []u32 = util.time_seed_array(2)
|
seed []u32 = seed.time_seed_array(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
__global ( default_rng &wyrand.WyRandRNG )
|
__global ( default_rng &wyrand.WyRandRNG )
|
||||||
|
@ -141,10 +141,10 @@ pub fn string(len int) string {
|
||||||
mut buf := malloc(len)
|
mut buf := malloc(len)
|
||||||
for i in 0 .. len {
|
for i in 0 .. len {
|
||||||
unsafe {
|
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
|
// uuid_v4 generates a random (v4) UUID
|
||||||
|
@ -184,7 +184,7 @@ pub fn uuid_v4() string {
|
||||||
buf[14] = `4`
|
buf[14] = `4`
|
||||||
buf[buflen] = 0
|
buf[buflen] = 0
|
||||||
}
|
}
|
||||||
return unsafe {buf.vstring_with_len(buflen)}
|
return unsafe { buf.vstring_with_len(buflen) }
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -209,7 +209,7 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
|
||||||
mut i := 9
|
mut i := 9
|
||||||
for i >= 0 {
|
for i >= 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
buf[i] = ulid_encoding[t & 0x1F]
|
buf[i] = rand.ulid_encoding[t & 0x1F]
|
||||||
}
|
}
|
||||||
t = t >> 5
|
t = t >> 5
|
||||||
i--
|
i--
|
||||||
|
@ -219,7 +219,7 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
|
||||||
i = 10
|
i = 10
|
||||||
for i < 19 {
|
for i < 19 {
|
||||||
unsafe {
|
unsafe {
|
||||||
buf[i] = ulid_encoding[x & 0x1F]
|
buf[i] = rand.ulid_encoding[x & 0x1F]
|
||||||
}
|
}
|
||||||
x = x >> 5
|
x = x >> 5
|
||||||
i++
|
i++
|
||||||
|
@ -228,7 +228,7 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
|
||||||
x = default_rng.u64()
|
x = default_rng.u64()
|
||||||
for i < 26 {
|
for i < 26 {
|
||||||
unsafe {
|
unsafe {
|
||||||
buf[i] = ulid_encoding[x & 0x1F]
|
buf[i] = rand.ulid_encoding[x & 0x1F]
|
||||||
}
|
}
|
||||||
x = x >> 5
|
x = x >> 5
|
||||||
i++
|
i++
|
||||||
|
@ -236,5 +236,5 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
|
||||||
unsafe {
|
unsafe {
|
||||||
buf[26] = 0
|
buf[26] = 0
|
||||||
}
|
}
|
||||||
return unsafe {buf.vstring_with_len(buflen)}
|
return unsafe { buf.vstring_with_len(buflen) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn test_ulids_generated_in_the_same_millisecond_have_the_same_prefix() {
|
||||||
t := time.utc().unix_time_milli()
|
t := time.utc().unix_time_milli()
|
||||||
mut ulid1 := ''
|
mut ulid1 := ''
|
||||||
mut ulid2 := ''
|
mut ulid2 := ''
|
||||||
mut ulid3 := ''
|
mut ulid3 := ''
|
||||||
ulid1 = rand.ulid_at_millisecond(t)
|
ulid1 = rand.ulid_at_millisecond(t)
|
||||||
ulid2 = rand.ulid_at_millisecond(t)
|
ulid2 = rand.ulid_at_millisecond(t)
|
||||||
ulid3 = rand.ulid_at_millisecond(t)
|
ulid3 = rand.ulid_at_millisecond(t)
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -3,12 +3,13 @@
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module splitmix64
|
module splitmix64
|
||||||
|
|
||||||
|
import rand.seed
|
||||||
import rand.util
|
import rand.util
|
||||||
|
|
||||||
// SplitMix64RNG ported from http://xoshiro.di.unimi.it/splitmix64.c
|
// SplitMix64RNG ported from http://xoshiro.di.unimi.it/splitmix64.c
|
||||||
pub struct SplitMix64RNG {
|
pub struct SplitMix64RNG {
|
||||||
mut:
|
mut:
|
||||||
state u64 = util.time_seed_64()
|
state u64 = seed.time_seed_64()
|
||||||
has_extra bool
|
has_extra bool
|
||||||
extra u32
|
extra u32
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import math
|
import math
|
||||||
import rand.splitmix64
|
import rand.splitmix64
|
||||||
import rand.util
|
import rand.seed
|
||||||
|
|
||||||
const (
|
const (
|
||||||
range_limit = 40
|
range_limit = 40
|
||||||
|
@ -16,7 +16,7 @@ const (
|
||||||
|
|
||||||
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
bound_u64 := u64(bound)
|
bound_u64 := u64(bound)
|
||||||
mut randoms := []u64{len:(20)}
|
mut randoms := []u64{len: (20)}
|
||||||
mut rnd := splitmix64.SplitMix64RNG{}
|
mut rnd := splitmix64.SplitMix64RNG{}
|
||||||
rnd.seed(seed_data)
|
rnd.seed(seed_data)
|
||||||
for i in 0 .. 20 {
|
for i in 0 .. 20 {
|
||||||
|
@ -26,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_splitmix64_reproducibility() {
|
fn test_splitmix64_reproducibility() {
|
||||||
seed_data := util.time_seed_array(2)
|
seed_data := seed.time_seed_array(2)
|
||||||
randoms1 := gen_randoms(seed_data, 1000)
|
randoms1 := gen_randoms(seed_data, 1000)
|
||||||
randoms2 := gen_randoms(seed_data, 1000)
|
randoms2 := gen_randoms(seed_data, 1000)
|
||||||
assert randoms1.len == randoms2.len
|
assert randoms1.len == randoms2.len
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
module sys
|
module sys
|
||||||
|
|
||||||
import math.bits
|
import math.bits
|
||||||
|
import rand.seed
|
||||||
import rand.util
|
import rand.util
|
||||||
|
|
||||||
// Implementation note:
|
// Implementation note:
|
||||||
|
@ -23,8 +24,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
fn calculate_iterations_for(bits int) int {
|
fn calculate_iterations_for(bits int) int {
|
||||||
base := bits / rand_bitsize
|
base := bits / sys.rand_bitsize
|
||||||
extra := if bits % rand_bitsize == 0 { 0 } else { 1 }
|
extra := if bits % sys.rand_bitsize == 0 { 0 } else { 1 }
|
||||||
return base + extra
|
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.
|
// SysRNG is the PRNG provided by default in the libc implementiation that V uses.
|
||||||
pub struct SysRNG {
|
pub struct SysRNG {
|
||||||
mut:
|
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.
|
// 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)
|
exit(1)
|
||||||
}
|
}
|
||||||
r.seed = seed_data[0]
|
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
|
// r.default_rand() exposes the default behavior of the system's RNG
|
||||||
|
@ -63,8 +64,8 @@ pub fn (r SysRNG) default_rand() int {
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (r SysRNG) u32() u32 {
|
pub fn (r SysRNG) u32() u32 {
|
||||||
mut result := u32(C.rand())
|
mut result := u32(C.rand())
|
||||||
for i in 1 .. u32_iter_count {
|
for i in 1 .. sys.u32_iter_count {
|
||||||
result = result ^ (u32(C.rand()) << (rand_bitsize * i))
|
result = result ^ (u32(C.rand()) << (sys.rand_bitsize * i))
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -73,8 +74,8 @@ pub fn (r SysRNG) u32() u32 {
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (r SysRNG) u64() u64 {
|
pub fn (r SysRNG) u64() u64 {
|
||||||
mut result := u64(C.rand())
|
mut result := u64(C.rand())
|
||||||
for i in 1 .. u64_iter_count {
|
for i in 1 .. sys.u64_iter_count {
|
||||||
result = result ^ (u64(C.rand()) << (rand_bitsize * i))
|
result = result ^ (u64(C.rand()) << (sys.rand_bitsize * i))
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module util
|
module util
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
// Commonly used constants across RNGs - some taken from "Numerical Recipes".
|
// Commonly used constants across RNGs - some taken from "Numerical Recipes".
|
||||||
pub const (
|
pub const (
|
||||||
lower_mask = u64(0x00000000FFFFFFFF)
|
lower_mask = u64(0x00000000FFFFFFFF)
|
||||||
|
@ -15,37 +13,3 @@ pub const (
|
||||||
u31_mask = u32(0x7FFFFFFF)
|
u31_mask = u32(0x7FFFFFFF)
|
||||||
u63_mask = u64(0x7FFFFFFFFFFFFFFF)
|
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
module wyrand
|
module wyrand
|
||||||
|
|
||||||
import math.bits
|
import math.bits
|
||||||
|
import rand.seed
|
||||||
import rand.util
|
import rand.util
|
||||||
import hash as wyhash
|
import hash
|
||||||
|
|
||||||
// Redefinition of some constants that we will need for pseudorandom number generation.
|
// Redefinition of some constants that we will need for pseudorandom number generation.
|
||||||
const (
|
const (
|
||||||
|
@ -16,7 +17,7 @@ const (
|
||||||
// WyRandRNG is a RNG based on the WyHash hashing algorithm.
|
// WyRandRNG is a RNG based on the WyHash hashing algorithm.
|
||||||
pub struct WyRandRNG {
|
pub struct WyRandRNG {
|
||||||
mut:
|
mut:
|
||||||
state u64 = util.time_seed_64()
|
state u64 = seed.time_seed_64()
|
||||||
has_extra bool
|
has_extra bool
|
||||||
extra u32
|
extra u32
|
||||||
}
|
}
|
||||||
|
@ -51,9 +52,9 @@ pub fn (mut rng WyRandRNG) u32() u32 {
|
||||||
pub fn (mut rng WyRandRNG) u64() u64 {
|
pub fn (mut rng WyRandRNG) u64() u64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut seed1 := rng.state
|
mut seed1 := rng.state
|
||||||
seed1 += wyp0
|
seed1 += wyrand.wyp0
|
||||||
rng.state = seed1
|
rng.state = seed1
|
||||||
return wyhash.wymum(seed1 ^ wyp1, seed1)
|
return hash.wymum(seed1 ^ wyrand.wyp1, seed1)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import math
|
import math
|
||||||
import rand.util
|
import rand.seed
|
||||||
import rand.wyrand
|
import rand.wyrand
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -16,7 +16,7 @@ const (
|
||||||
|
|
||||||
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
bound_u64 := u64(bound)
|
bound_u64 := u64(bound)
|
||||||
mut randoms := []u64{len:(20)}
|
mut randoms := []u64{len: (20)}
|
||||||
mut rnd := wyrand.WyRandRNG{}
|
mut rnd := wyrand.WyRandRNG{}
|
||||||
rnd.seed(seed_data)
|
rnd.seed(seed_data)
|
||||||
for i in 0 .. 20 {
|
for i in 0 .. 20 {
|
||||||
|
@ -26,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_wyrand_reproducibility() {
|
fn test_wyrand_reproducibility() {
|
||||||
seed_data := util.time_seed_array(2)
|
seed_data := seed.time_seed_array(2)
|
||||||
randoms1 := gen_randoms(seed_data, 1000)
|
randoms1 := gen_randoms(seed_data, 1000)
|
||||||
randoms2 := gen_randoms(seed_data, 1000)
|
randoms2 := gen_randoms(seed_data, 1000)
|
||||||
assert randoms1.len == randoms2.len
|
assert randoms1.len == randoms2.len
|
||||||
|
|
Loading…
Reference in New Issue