rand: reorganize: phase 2

pull/5304/head
Hungry Blue Dev 2020-06-09 18:36:07 +05:30 committed by GitHub
parent 67fcce2d46
commit e649cf84e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 603 additions and 408 deletions

View File

@ -12,11 +12,11 @@ fn main() {
println('Generating $sample_size strings between $min_str_len - $max_str_len chars long...') println('Generating $sample_size strings between $min_str_len - $max_str_len chars long...')
mut bytepile := []byte{} mut bytepile := []byte{}
for _ in 0 .. sample_size * max_str_len { for _ in 0 .. sample_size * max_str_len {
bytepile << byte(40 + rand.next(125 - 40)) bytepile << byte(rand.int_in_range(40, 125))
} }
mut str_lens := []int{} mut str_lens := []int{}
for _ in 0 .. sample_size { for _ in 0 .. sample_size {
str_lens << min_str_len + rand.next(max_str_len - min_str_len) str_lens << rand.int_in_range(min_str_len, max_str_len)
} }
println('Hashing each of the generated strings...') println('Hashing each of the generated strings...')
t0 := time.ticks() t0 := time.ticks()

View File

@ -22,6 +22,7 @@ const (
] ]
skip_on_windows = [ skip_on_windows = [
'vlib/orm/orm_test.v', 'vlib/orm/orm_test.v',
'vlib/net/websocket/ws_test.v',
] ]
skip_on_non_windows = []string{} skip_on_non_windows = []string{}
skip_on_macos = []string{} skip_on_macos = []string{}

View File

@ -236,7 +236,7 @@ fn intersect(r Ray, spheres &Sphere, nspheres int) (bool, f64, int){
// some casual random function, try to avoid the 0 // some casual random function, try to avoid the 0
fn rand_f64() f64 { fn rand_f64() f64 {
x := (C.rand()+1) & 0x3FFF_FFFF x := (rand.intn(cache_len)+1) & 0x3FFF_FFFF
return f64(x)/f64(0x3FFF_FFFF) return f64(x)/f64(0x3FFF_FFFF)
} }
@ -318,7 +318,7 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
//r1 := f64(2.0 * math.pi) * rand_f64() //r1 := f64(2.0 * math.pi) * rand_f64()
// tabbed speed-up // tabbed speed-up
r1 := C.rand() & cache_mask r1 := rand.intn(cache_len) & cache_mask
r2 := rand_f64() r2 := rand_f64()
r2s := math.sqrt(r2) r2s := math.sqrt(r2)
@ -465,9 +465,8 @@ fn main() {
height = os.args[5].int() height = os.args[5].int()
} }
// init the rand, using the same seed allows to obtain the same result in different runs // change the seed for a different result
// change the seed from 2020 for different results rand.seed([u32(2020), 0])
rand.seed(2020)
t1:=time.ticks() t1:=time.ticks()

View File

@ -7,11 +7,10 @@ const (
) )
fn main() { fn main() {
rand.seed(int(time.now().unix)) rand.intn(gen_max) // skip the first
rand.next(gen_max) // skip the first
mut arr := []int{} mut arr := []int{}
for _ in 0..gen_len { for _ in 0..gen_len {
arr << rand.next(gen_max) arr << rand.intn(gen_max)
} }
println('length of random array is $arr.len') println('length of random array is $arr.len')
println('before quick sort whether array is sorted: ${is_sorted(arr)}') println('before quick sort whether array is sorted: ${is_sorted(arr)}')

View File

@ -2,9 +2,7 @@ import rand
import time import time
fn main() { fn main() {
rand.seed(int(time.now().unix))
for _ in 0..10 { for _ in 0..10 {
println('${rand.next(255)}.${rand.next(255)}.${rand.next(255)}.${rand.next(255)}') println('${rand.intn(255)}.${rand.intn(255)}.${rand.intn(255)}.${rand.intn(255)}')
} }
} }

View File

@ -193,7 +193,6 @@ fn main() {
fn (mut g Game) init_game() { fn (mut g Game) init_game() {
g.parse_tetros() g.parse_tetros()
rand.seed(int(time.now().unix))
g.generate_tetro() g.generate_tetro()
g.field = [] g.field = []
// Generate the field, fill it with 0's, add -1's on each edge // Generate the field, fill it with 0's, add -1's on each edge
@ -300,7 +299,7 @@ fn (mut g Game) delete_completed_line(y int) {
fn (mut g Game) generate_tetro() { fn (mut g Game) generate_tetro() {
g.pos_y = 0 g.pos_y = 0
g.pos_x = field_width / 2 - tetro_size / 2 g.pos_x = field_width / 2 - tetro_size / 2
g.tetro_idx = rand.next(b_tetros.len) g.tetro_idx = rand.intn(b_tetros.len)
g.rotation_idx = 0 g.rotation_idx = 0
g.get_tetro() g.get_tetro()
} }

View File

@ -81,7 +81,7 @@ fn get_bet(money int) int {
} }
bet = line.int() bet = line.int()
if bet <= 0 { if bet <= 0 {
println('error: $line is not heigher than 1.') println('error: $line is not higher than 1.')
continue continue
} else if bet > money { } else if bet > money {
println('error: $line is more money than you have.') println('error: $line is more money than you have.')
@ -92,8 +92,7 @@ fn get_bet(money int) int {
fn run_wheel(bet_nbr int, _bet int) int { fn run_wheel(bet_nbr int, _bet int) int {
mut bet := _bet mut bet := _bet
rand.seed(int(time.now().unix)) winning_nbr := rand.intn(50)
winning_nbr := rand.next(50)
print('Roulette Wheel spinning... and stops on the number $winning_nbr which is a ') print('Roulette Wheel spinning... and stops on the number $winning_nbr which is a ')
if winning_nbr % 2 == 1 { if winning_nbr % 2 == 1 {
println(odd) println(odd)
@ -115,7 +114,7 @@ fn run_wheel(bet_nbr int, _bet int) int {
fn is_broke(money int) bool { fn is_broke(money int) bool {
if money <= 0 { if money <= 0 {
println('You\'broke, the game is over..') println('You\'re broke, the game is over..')
return false return false
} else { } else {
quit := Options{'yes', 'y'} quit := Options{'yes', 'y'}

View File

@ -19,16 +19,15 @@ fn test_bf_set_clear_toggle_get() {
} }
fn test_bf_and_not_or_xor() { fn test_bf_and_not_or_xor() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input1 := bitfield.new(len) mut input1 := bitfield.new(len)
mut input2 := bitfield.new(len) mut input2 := bitfield.new(len)
mut i := 0 mut i := 0
for i < len { for i < len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input1.set_bit(i) input1.set_bit(i)
} }
if rand.next(2) == 1{ if rand.intn(2) == 1{
input2.set_bit(i) input2.set_bit(i)
} }
i++ i++
@ -46,11 +45,10 @@ fn test_bf_and_not_or_xor() {
} }
fn test_clone_cmp() { fn test_clone_cmp() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i in 0..len { for i in 0..len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input.set_bit(i) input.set_bit(i)
} }
} }
@ -60,11 +58,10 @@ fn test_clone_cmp() {
} }
fn test_slice_join() { fn test_slice_join() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i in 0..len { for i in 0..len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input.set_bit(i) input.set_bit(i)
} }
} }
@ -83,12 +80,11 @@ fn test_slice_join() {
} }
fn test_pop_count() { fn test_pop_count() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut count0 := 0 mut count0 := 0
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i in 0..len { for i in 0..len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input.set_bit(i) input.set_bit(i)
count0++ count0++
} }
@ -98,13 +94,12 @@ fn test_pop_count() {
} }
fn test_hamming() { fn test_hamming() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut count := 0 mut count := 0
mut input1 := bitfield.new(len) mut input1 := bitfield.new(len)
mut input2 := bitfield.new(len) mut input2 := bitfield.new(len)
for i in 0..len { for i in 0..len {
match rand.next(4) { match rand.intn(4) {
0, 1 { 0, 1 {
input1.set_bit(i) input1.set_bit(i)
count++ count++
@ -138,11 +133,10 @@ fn test_bf_from_bytes() {
} }
fn test_bf_from_str() { fn test_bf_from_str() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := '' mut input := ''
for _ in 0..len { for _ in 0..len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input = input + '1' input = input + '1'
} }
else { else {
@ -160,11 +154,10 @@ fn test_bf_from_str() {
} }
fn test_bf_bf2str() { fn test_bf_bf2str() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i in 0..len { for i in 0..len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input.set_bit(i) input.set_bit(i)
} }
} }
@ -188,7 +181,6 @@ fn test_bf_bf2str() {
} }
fn test_bf_set_all() { fn test_bf_set_all() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
input.set_all() input.set_all()
@ -202,11 +194,10 @@ fn test_bf_set_all() {
} }
fn test_bf_clear_all() { fn test_bf_clear_all() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i in 0..len { for i in 0..len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input.set_bit(i) input.set_bit(i)
} }
} }
@ -221,11 +212,10 @@ fn test_bf_clear_all() {
} }
fn test_bf_reverse() { fn test_bf_reverse() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i in 0..len { for i in 0..len {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
input.set_bit(i) input.set_bit(i)
} }
} }
@ -241,11 +231,10 @@ fn test_bf_reverse() {
} }
fn test_bf_resize() { fn test_bf_resize() {
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(rand.next(len) + 1) mut input := bitfield.new(rand.intn(len) + 1)
for _ in 0..100 { for _ in 0..100 {
input.resize(rand.next(len) + 1) input.resize(rand.intn(len) + 1)
input.set_bit(input.get_size() - 1) input.set_bit(input.get_size() - 1)
} }
assert input.get_bit(input.get_size() - 1) == 1 assert input.get_bit(input.get_size() - 1) == 1
@ -259,7 +248,6 @@ fn test_bf_pos() {
* all haystacks here contain exactly one instanse of needle, * all haystacks here contain exactly one instanse of needle,
* so search should return non-negative-values * so search should return non-negative-values
**/ **/
rand.seed(int(time.now().unix))
len := 80 len := 80
mut result := 1 mut result := 1
for i := 1; i < len; i++ { // needle size for i := 1; i < len; i++ { // needle size
@ -269,13 +257,13 @@ fn test_bf_pos() {
// fill the needle with random values // fill the needle with random values
for k in 0..i { for k in 0..i {
if rand.next(2) == 1 { if rand.intn(2) == 1 {
needle.set_bit(k) needle.set_bit(k)
} }
} }
// make sure the needle contains at least one set bit, selected randomly // make sure the needle contains at least one set bit, selected randomly
r := rand.next(i) r := rand.intn(i)
needle.set_bit(r) needle.set_bit(r)
// create the haystack, make sure it contains the needle // create the haystack, make sure it contains the needle
@ -322,11 +310,10 @@ fn test_bf_rotate() {
} }
fn test_bf_printing(){ fn test_bf_printing(){
rand.seed(int(time.now().unix))
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i in 0..len { for i in 0..len {
if rand.next(2) == 0 { if rand.intn(2) == 0 {
input.set_bit(i) input.set_bit(i)
} }
} }

View File

@ -1,8 +1,6 @@
module websocket module websocket
import time
import rand import rand
import math
import crypto.sha1 import crypto.sha1
import encoding.base64 import encoding.base64
@ -20,10 +18,7 @@ fn htonl64(payload_len u64) byteptr {
} }
fn create_masking_key() []byte { fn create_masking_key() []byte {
t := time.ticks() mask_bit := byte(rand.intn(255))
tseq := t % 23237671
mut rnd := rand.new_pcg32(u64(t), u64(tseq))
mask_bit := byte(rnd.bounded_next(u32(math.max_i32)))
buf := [`0`].repeat(4) buf := [`0`].repeat(4)
C.memcpy(buf.data, &mask_bit, 4) C.memcpy(buf.data, &mask_bit, 4)
return buf return buf
@ -46,7 +41,7 @@ fn get_nonce(nonce_size int) string {
mut nonce := []byte{len: nonce_size, cap: nonce_size} mut nonce := []byte{len: nonce_size, cap: nonce_size}
alphanum := '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz' alphanum := '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz'
for i in 0 .. nonce_size { for i in 0 .. nonce_size {
nonce[i] = alphanum[rand.next(61)] nonce[i] = alphanum[rand.intn(alphanum.len)]
} }
return tos(nonce.data, nonce.len).clone() return tos(nonce.data, nonce.len).clone()
} }

View File

@ -0,0 +1,46 @@
# Quickstart
The V `rand` module provides two main ways in which users can generate pseudorandom numbers:
1. Through top-level functions in the `rand` module.
- `import rand` - Import the `rand` module.
- `rand.seed(seed_data)` to seed (optional).
- Use `rand.int()`, `rand.u32n(max)`, etc.
2. Through a generator of choice. The PRNGs are included in their respective submodules.
- `import rand.pcg32` - Import the module of the PRNG required.
- `mut rng := pcg32.PCG32RNG{}` - Initialize the struct. Note that the **`mut`** is important.
- `rng.seed(seed_data)` - optionally seed it with an array of `u32` values.
- Use `rng.int()`, `rng.u32n(max)`, etc.
# General Background
A PRNG is a Pseudo Random Number Generator. Computers cannot generate truly random numbers without an external source of noise or entropy. We can use algorithms to generate sequences of seemingly random numbers, but their outputs will always be deterministic. This is often useful for simulations that need the same starting seed.
If you need truly random numbers that are going to be used for cryptography, use the `crypto.rand` module.
# Guaranteed functions
The following 21 functions are guaranteed to be supported by `rand` as well as the individual PRNGs.
- `seed(seed_data)` where `seed_data` is an array of `u32` values. Different generators require different number of bits as the initial seed. The smallest is 32-bits, required by `sys.SysRNG`. Most others require 64-bits or 2 `u32` values.
- `u32()`, `u64()`, `int()`, `i64()`, `f32()`, `f64()`
- `u32n(max)`, `u64n(max)`, `intn(max)`, `i64n(max)`, `f32n(max)`, `f64n(max)`
- `u32_in_range(min, max)`, `u64_in_range(min, max)`, `int_in_range(min, max)`, `i64_in_range(min, max)`, `f32_in_range(min, max)`, `f64_in_range(min, max)`
- `int31()`, `int63()`
# Utility Functions
All the generators are time-seeded. The helper functions publicly available in `rand.util` module are:
1. `time_seed_array()` - returns a `[]u32` that can be directly plugged into the `seed()` functions.
2. `time_seed_32()` and `time_seed_64()` - 32-bit and 64-bit values respectively that are generated from the current time.
# Caveats
Note that the `sys.SysRNG` struct (in the C backend) uses `C.srand()` which sets the seed globally. Consequently, all instances of the RNG will be affected. This problem does not arise for the other RNGs. A workaround (if you _must_ use the libc RNG) is to:
1. Seed the first instance.
2. Generate all values required.
3. Seed the second instance.
4. Generate all values required.
5. And so on...

View File

@ -1,9 +1,10 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module mt19937
import math.bits import math.bits
import rand.util
/* /*
C++ functions for MT19937, with initialization improved 2002/2/10. C++ functions for MT19937, with initialization improved 2002/2/10.
@ -58,7 +59,7 @@ const (
// A generator that uses the Mersenne Twister algorithm with period 2^19937 // A generator that uses the Mersenne Twister algorithm with period 2^19937
pub struct MT19937RNG { pub struct MT19937RNG {
mut: mut:
state []u64 = calculate_state(time_seed_array(2), mut []u64{len: nn}) state []u64 = calculate_state(util.time_seed_array(2), mut []u64{len: nn})
mti int = nn mti int = nn
next_rnd u32 = 0 next_rnd u32 = 0
has_next bool = false has_next bool = false

View File

@ -1,5 +1,6 @@
import rand import mt19937
import math import math
import rand.util
const ( const (
range_limit = 40 range_limit = 40
@ -14,7 +15,7 @@ const (
) )
fn mt19937_basic_test() { fn mt19937_basic_test() {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed([u32(0xdeadbeef)]) rng.seed([u32(0xdeadbeef)])
target := [956529277, 3842322136, 3319553134, 1843186657, 2704993644, 595827513, 938518626, target := [956529277, 3842322136, 3319553134, 1843186657, 2704993644, 595827513, 938518626,
1676224337, 3221315650, 1819026461] 1676224337, 3221315650, 1819026461]
@ -26,7 +27,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(0)].repeat(20) mut randoms := [u64(0)].repeat(20)
mut rnd := rand.MT19937RNG{} mut rnd := mt19937.MT19937RNG{}
rnd.seed(seed_data) rnd.seed(seed_data)
for i in 0 .. 20 { for i in 0 .. 20 {
randoms[i] = rnd.u64n(bound_u64) randoms[i] = rnd.u64n(bound_u64)
@ -35,7 +36,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
} }
fn test_mt19937_reproducibility() { fn test_mt19937_reproducibility() {
seed_data := rand.time_seed_array(2) seed_data := util.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
@ -61,7 +62,7 @@ fn test_mt19937_variability() {
// at fault, try changing the seed values. Repeated values are // at fault, try changing the seed values. Repeated values are
// improbable but not impossible. // improbable but not impossible.
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
mut values := []u64{cap: value_count} mut values := []u64{cap: value_count}
for i in 0 .. value_count { for i in 0 .. value_count {
@ -73,7 +74,7 @@ fn test_mt19937_variability() {
} }
} }
fn check_uniformity_u64(mut rng rand.MT19937RNG, range u64) { fn check_uniformity_u64(mut rng mt19937.MT19937RNG, range u64) {
range_f64 := f64(range) range_f64 := f64(range)
expected_mean := range_f64 / 2.0 expected_mean := range_f64 / 2.0
mut variance := 0.0 mut variance := 0.0
@ -91,7 +92,7 @@ fn check_uniformity_u64(mut rng rand.MT19937RNG, range u64) {
fn test_mt19937_uniformity_u64() { fn test_mt19937_uniformity_u64() {
ranges := [14019545, 80240, 130] ranges := [14019545, 80240, 130]
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for range in ranges { for range in ranges {
check_uniformity_u64(mut rng, u64(range)) check_uniformity_u64(mut rng, u64(range))
@ -99,7 +100,7 @@ fn test_mt19937_uniformity_u64() {
} }
} }
fn check_uniformity_f64(mut rng rand.MT19937RNG) { fn check_uniformity_f64(mut rng mt19937.MT19937RNG) {
expected_mean := 0.5 expected_mean := 0.5
mut variance := 0.0 mut variance := 0.0
for _ in 0 .. sample_size { for _ in 0 .. sample_size {
@ -116,19 +117,19 @@ fn check_uniformity_f64(mut rng rand.MT19937RNG) {
fn test_mt19937_uniformity_f64() { fn test_mt19937_uniformity_f64() {
// The f64 version // The f64 version
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
check_uniformity_f64(mut rng) check_uniformity_f64(mut rng)
} }
} }
fn test_mt19937_u32n() { fn test_mt19937_u32n() {
max := 16384 max := u32(16384)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32n(u32(max)) value := rng.u32n(max)
assert value >= 0 assert value >= 0
assert value < max assert value < max
} }
@ -138,7 +139,7 @@ fn test_mt19937_u32n() {
fn test_mt19937_u64n() { fn test_mt19937_u64n() {
max := u64(379091181005) max := u64(379091181005)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64n(max) value := rng.u64n(max)
@ -149,13 +150,13 @@ fn test_mt19937_u64n() {
} }
fn test_mt19937_u32_in_range() { fn test_mt19937_u32_in_range() {
max := 484468466 max := u32(484468466)
min := 316846 min := u32(316846)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32_in_range(u32(min), u32(max)) value := rng.u32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -166,7 +167,7 @@ fn test_mt19937_u64_in_range() {
max := u64(216468454685163) max := u64(216468454685163)
min := u64(6848646868) min := u64(6848646868)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64_in_range(min, max) value := rng.u64_in_range(min, max)
@ -180,7 +181,7 @@ fn test_mt19937_int31() {
max_u31 := 0x7FFFFFFF max_u31 := 0x7FFFFFFF
sign_mask := 0x80000000 sign_mask := 0x80000000
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int31() value := rng.int31()
@ -196,7 +197,7 @@ fn test_mt19937_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF) max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000) sign_mask := i64(0x8000000000000000)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int63() value := rng.int63()
@ -210,7 +211,7 @@ fn test_mt19937_int63() {
fn test_mt19937_intn() { fn test_mt19937_intn() {
max := 2525642 max := 2525642
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.intn(max) value := rng.intn(max)
@ -223,7 +224,7 @@ fn test_mt19937_intn() {
fn test_mt19937_i64n() { fn test_mt19937_i64n() {
max := i64(3246727724653636) max := i64(3246727724653636)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64n(max) value := rng.i64n(max)
@ -237,7 +238,7 @@ fn test_mt19937_int_in_range() {
min := -4252 min := -4252
max := 1034 max := 1034
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int_in_range(min, max) value := rng.int_in_range(min, max)
@ -251,7 +252,7 @@ fn test_mt19937_i64_in_range() {
min := i64(-24095) min := i64(-24095)
max := i64(324058) max := i64(324058)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64_in_range(min, max) value := rng.i64_in_range(min, max)
@ -263,7 +264,7 @@ fn test_mt19937_i64_in_range() {
fn test_mt19937_f32() { fn test_mt19937_f32() {
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32()
@ -275,7 +276,7 @@ fn test_mt19937_f32() {
fn test_mt19937_f64() { fn test_mt19937_f64() {
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64()
@ -288,7 +289,7 @@ fn test_mt19937_f64() {
fn test_mt19937_f32n() { fn test_mt19937_f32n() {
max := f32(357.0) max := f32(357.0)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32n(max) value := rng.f32n(max)
@ -301,7 +302,7 @@ fn test_mt19937_f32n() {
fn test_mt19937_f64n() { fn test_mt19937_f64n() {
max := 1.52e6 max := 1.52e6
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64n(max) value := rng.f64n(max)
@ -315,7 +316,7 @@ fn test_mt19937_f32_in_range() {
min := f32(-24.0) min := f32(-24.0)
max := f32(125.0) max := f32(125.0)
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32_in_range(min, max) value := rng.f32_in_range(min, max)
@ -329,7 +330,7 @@ fn test_mt19937_f64_in_range() {
min := -548.7 min := -548.7
max := 5015.2 max := 5015.2
for seed in seeds { for seed in seeds {
mut rng := rand.MT19937RNG{} mut rng := mt19937.MT19937RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64_in_range(min, max) value := rng.f64_in_range(min, max)

View File

@ -1,14 +1,15 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module musl
import math.bits import math.bits
import rand.util
// Ported from https://git.musl-libc.org/cgit/musl/tree/src/prng/rand_r.c // 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 = time_seed_32() state u32 = util.time_seed_32()
} }
pub fn (mut rng MuslRNG) seed(seed_data []u32) { pub fn (mut rng MuslRNG) seed(seed_data []u32) {
@ -186,13 +187,13 @@ pub fn (mut rng MuslRNG) i64_in_range(min, max i64) i64 {
// rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng MuslRNG) f32() f32 { pub fn (mut rng MuslRNG) f32() f32 {
return f32(rng.u32()) / max_u32_as_f32 return f32(rng.u32()) / util.max_u32_as_f32
} }
// rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng MuslRNG) f64() f64 { pub fn (mut rng MuslRNG) f64() f64 {
return f64(rng.u64()) / max_u64_as_f64 return f64(rng.u64()) / util.max_u64_as_f64
} }
// rng.f32n() returns a pseudorandom f32 value in [0, max) // rng.f32n() returns a pseudorandom f32 value in [0, max)

View File

@ -1,5 +1,6 @@
import rand import musl
import math import math
import rand.util
const ( const (
range_limit = 40 range_limit = 40
@ -16,7 +17,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(0)].repeat(20) mut randoms := [u64(0)].repeat(20)
mut rnd := rand.MuslRNG{} mut rnd := musl.MuslRNG{}
rnd.seed(seed_data) rnd.seed(seed_data)
for i in 0 .. 20 { for i in 0 .. 20 {
randoms[i] = rnd.u64n(bound_u64) randoms[i] = rnd.u64n(bound_u64)
@ -25,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
} }
fn test_musl_reproducibility() { fn test_musl_reproducibility() {
seed_data := rand.time_seed_array(1) seed_data := util.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
@ -51,7 +52,7 @@ fn test_musl_variability() {
// at fault, try changing the seed values. Repeated values are // at fault, try changing the seed values. Repeated values are
// improbable but not impossible. // improbable but not impossible.
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
mut values := []u64{cap: value_count} mut values := []u64{cap: value_count}
for i in 0 .. value_count { for i in 0 .. value_count {
@ -63,7 +64,7 @@ fn test_musl_variability() {
} }
} }
fn check_uniformity_u64(mut rng rand.MuslRNG, range u64) { fn check_uniformity_u64(mut rng musl.MuslRNG, range u64) {
range_f64 := f64(range) range_f64 := f64(range)
expected_mean := range_f64 / 2.0 expected_mean := range_f64 / 2.0
mut variance := 0.0 mut variance := 0.0
@ -81,7 +82,7 @@ fn check_uniformity_u64(mut rng rand.MuslRNG, range u64) {
fn test_musl_uniformity_u64() { fn test_musl_uniformity_u64() {
ranges := [14019545, 80240, 130] ranges := [14019545, 80240, 130]
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for range in ranges { for range in ranges {
check_uniformity_u64(mut rng, u64(range)) check_uniformity_u64(mut rng, u64(range))
@ -89,7 +90,7 @@ fn test_musl_uniformity_u64() {
} }
} }
fn check_uniformity_f64(mut rng rand.MuslRNG) { fn check_uniformity_f64(mut rng musl.MuslRNG) {
expected_mean := 0.5 expected_mean := 0.5
mut variance := 0.0 mut variance := 0.0
for _ in 0 .. sample_size { for _ in 0 .. sample_size {
@ -106,19 +107,19 @@ fn check_uniformity_f64(mut rng rand.MuslRNG) {
fn test_musl_uniformity_f64() { fn test_musl_uniformity_f64() {
// The f64 version // The f64 version
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
check_uniformity_f64(mut rng) check_uniformity_f64(mut rng)
} }
} }
fn test_musl_u32n() { fn test_musl_u32n() {
max := 16384 max := u32(16384)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32n(u32(max)) value := rng.u32n(max)
assert value >= 0 assert value >= 0
assert value < max assert value < max
} }
@ -128,7 +129,7 @@ fn test_musl_u32n() {
fn test_musl_u64n() { fn test_musl_u64n() {
max := u64(379091181005) max := u64(379091181005)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64n(max) value := rng.u64n(max)
@ -139,13 +140,13 @@ fn test_musl_u64n() {
} }
fn test_musl_u32_in_range() { fn test_musl_u32_in_range() {
max := 484468466 max := u32(484468466)
min := 316846 min := u32(316846)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32_in_range(u64(min), u64(max)) value := rng.u32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -156,7 +157,7 @@ fn test_musl_u64_in_range() {
max := u64(216468454685163) max := u64(216468454685163)
min := u64(6848646868) min := u64(6848646868)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64_in_range(min, max) value := rng.u64_in_range(min, max)
@ -170,7 +171,7 @@ fn test_musl_int31() {
max_u31 := 0x7FFFFFFF max_u31 := 0x7FFFFFFF
sign_mask := 0x80000000 sign_mask := 0x80000000
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int31() value := rng.int31()
@ -186,7 +187,7 @@ fn test_musl_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF) max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000) sign_mask := i64(0x8000000000000000)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int63() value := rng.int63()
@ -200,7 +201,7 @@ fn test_musl_int63() {
fn test_musl_intn() { fn test_musl_intn() {
max := 2525642 max := 2525642
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.intn(max) value := rng.intn(max)
@ -213,7 +214,7 @@ fn test_musl_intn() {
fn test_musl_i64n() { fn test_musl_i64n() {
max := i64(3246727724653636) max := i64(3246727724653636)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64n(max) value := rng.i64n(max)
@ -227,7 +228,7 @@ fn test_musl_int_in_range() {
min := -4252 min := -4252
max := 1034 max := 1034
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int_in_range(min, max) value := rng.int_in_range(min, max)
@ -241,7 +242,7 @@ fn test_musl_i64_in_range() {
min := i64(-24095) min := i64(-24095)
max := i64(324058) max := i64(324058)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64_in_range(min, max) value := rng.i64_in_range(min, max)
@ -253,7 +254,7 @@ fn test_musl_i64_in_range() {
fn test_musl_f32() { fn test_musl_f32() {
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32()
@ -265,7 +266,7 @@ fn test_musl_f32() {
fn test_musl_f64() { fn test_musl_f64() {
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64()
@ -278,10 +279,10 @@ fn test_musl_f64() {
fn test_musl_f32n() { fn test_musl_f32n() {
max := f32(357.0) max := f32(357.0)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -291,10 +292,10 @@ fn test_musl_f32n() {
fn test_musl_f64n() { fn test_musl_f64n() {
max := 1.52e6 max := 1.52e6
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -305,10 +306,10 @@ fn test_musl_f32_in_range() {
min := f32(-24.0) min := f32(-24.0)
max := f32(125.0) max := f32(125.0)
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -319,10 +320,10 @@ fn test_musl_f64_in_range() {
min := -548.7 min := -548.7
max := 5015.2 max := 5015.2
for seed in seeds { for seed in seeds {
mut rng := rand.MuslRNG{} mut rng := musl.MuslRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }

View File

@ -1,26 +1,17 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module pcg32
import rand.util
// Ported from http://www.pcg-random.org/download.html, // Ported from http://www.pcg-random.org/download.html,
// https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c, and // https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c, and
// 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) ^ time_seed_64() state u64 = u64(0x853c49e6748fea9b) ^ util.time_seed_64()
inc u64 = u64(0xda3e39cb94b95bdb) ^ time_seed_64() inc u64 = u64(0xda3e39cb94b95bdb) ^ util.time_seed_64()
}
// TODO: Remove in Phase 2 of reorganizing Random
pub fn new_pcg32(init_state, init_seq u64) PCG32RNG {
mut rng := PCG32RNG{}
rng.seed([u32(init_state), u32(init_state >> 32), u32(init_seq), u32(init_seq >> 32)])
return rng
}
pub fn (mut rng PCG32RNG) bounded_next(bound u32) u32 {
return rng.u32n(bound)
} }
// rng.seed(seed_data) - seed the PCG32RNG with 4 u32 values. // rng.seed(seed_data) - seed the PCG32RNG with 4 u32 values.
@ -184,13 +175,13 @@ pub fn (mut rng PCG32RNG) i64_in_range(min, max i64) i64 {
// rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng PCG32RNG) f32() f32 { pub fn (mut rng PCG32RNG) f32() f32 {
return f32(rng.u32()) / max_u32_as_f32 return f32(rng.u32()) / util.max_u32_as_f32
} }
// rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng PCG32RNG) f64() f64 { pub fn (mut rng PCG32RNG) f64() f64 {
return f64(rng.u64()) / max_u64_as_f64 return f64(rng.u64()) / util.max_u64_as_f64
} }
// rng.f32n() returns a pseudorandom f32 value in [0, max) // rng.f32n() returns a pseudorandom f32 value in [0, max)

View File

@ -1,5 +1,6 @@
import rand
import math import math
import pcg32
import rand.util
const ( const (
range_limit = 40 range_limit = 40
@ -15,7 +16,7 @@ const (
fn gen_randoms(seed_data []u32, bound int) []u32 { fn gen_randoms(seed_data []u32, bound int) []u32 {
mut randoms := []u32{len: 20} mut randoms := []u32{len: 20}
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed_data) rng.seed(seed_data)
for i in 0 .. 20 { for i in 0 .. 20 {
randoms[i] = rng.u32n(u32(bound)) randoms[i] = rng.u32n(u32(bound))
@ -24,8 +25,8 @@ fn gen_randoms(seed_data []u32, bound int) []u32 {
} }
fn test_pcg32_reproducibility() { fn test_pcg32_reproducibility() {
randoms1 := gen_randoms(rand.time_seed_array(4), 1000) randoms1 := gen_randoms(util.time_seed_array(4), 1000)
randoms2 := gen_randoms(rand.time_seed_array(4), 1000) randoms2 := gen_randoms(util.time_seed_array(4), 1000)
assert randoms1.len == randoms2.len assert randoms1.len == randoms2.len
len := randoms1.len len := randoms1.len
for i in 0 .. len { for i in 0 .. len {
@ -49,7 +50,7 @@ fn test_pcg32_variability() {
// at fault, try changing the seed values. Repeated values are // at fault, try changing the seed values. Repeated values are
// improbable but not impossible. // improbable but not impossible.
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
mut values := []u64{cap: value_count} mut values := []u64{cap: value_count}
for i in 0 .. value_count { for i in 0 .. value_count {
@ -61,7 +62,7 @@ fn test_pcg32_variability() {
} }
} }
fn check_uniformity_u64(mut rng rand.PCG32RNG, range u64) { fn check_uniformity_u64(mut rng pcg32.PCG32RNG, range u64) {
range_f64 := f64(range) range_f64 := f64(range)
expected_mean := range_f64 / 2.0 expected_mean := range_f64 / 2.0
mut variance := 0.0 mut variance := 0.0
@ -79,7 +80,7 @@ fn check_uniformity_u64(mut rng rand.PCG32RNG, range u64) {
fn test_pcg32_uniformity_u64() { fn test_pcg32_uniformity_u64() {
ranges := [14019545, 80240, 130] ranges := [14019545, 80240, 130]
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for range in ranges { for range in ranges {
check_uniformity_u64(mut rng, u64(range)) check_uniformity_u64(mut rng, u64(range))
@ -87,7 +88,7 @@ fn test_pcg32_uniformity_u64() {
} }
} }
fn check_uniformity_f64(mut rng rand.PCG32RNG) { fn check_uniformity_f64(mut rng pcg32.PCG32RNG) {
expected_mean := 0.5 expected_mean := 0.5
mut variance := 0.0 mut variance := 0.0
for _ in 0 .. sample_size { for _ in 0 .. sample_size {
@ -104,19 +105,19 @@ fn check_uniformity_f64(mut rng rand.PCG32RNG) {
fn test_pcg32_uniformity_f64() { fn test_pcg32_uniformity_f64() {
// The f64 version // The f64 version
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
check_uniformity_f64(mut rng) check_uniformity_f64(mut rng)
} }
} }
fn test_pcg32_u32n() { fn test_pcg32_u32n() {
max := 16384 max := u32(16384)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32n(u32(max)) value := rng.u32n(max)
assert value >= 0 assert value >= 0
assert value < max assert value < max
} }
@ -126,7 +127,7 @@ fn test_pcg32_u32n() {
fn test_pcg32_u64n() { fn test_pcg32_u64n() {
max := u64(379091181005) max := u64(379091181005)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64n(max) value := rng.u64n(max)
@ -137,10 +138,10 @@ fn test_pcg32_u64n() {
} }
fn test_pcg32_u32_in_range() { fn test_pcg32_u32_in_range() {
max := 484468466 max := u64(484468466)
min := 316846 min := u64(316846)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32_in_range(u64(min), u64(max)) value := rng.u32_in_range(u64(min), u64(max))
@ -154,7 +155,7 @@ fn test_pcg32_u64_in_range() {
max := u64(216468454685163) max := u64(216468454685163)
min := u64(6848646868) min := u64(6848646868)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64_in_range(min, max) value := rng.u64_in_range(min, max)
@ -168,7 +169,7 @@ fn test_pcg32_int31() {
max_u31 := 0x7FFFFFFF max_u31 := 0x7FFFFFFF
sign_mask := 0x80000000 sign_mask := 0x80000000
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int31() value := rng.int31()
@ -184,7 +185,7 @@ fn test_pcg32_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF) max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000) sign_mask := i64(0x8000000000000000)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int63() value := rng.int63()
@ -198,7 +199,7 @@ fn test_pcg32_int63() {
fn test_pcg32_intn() { fn test_pcg32_intn() {
max := 2525642 max := 2525642
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.intn(max) value := rng.intn(max)
@ -211,7 +212,7 @@ fn test_pcg32_intn() {
fn test_pcg32_i64n() { fn test_pcg32_i64n() {
max := i64(3246727724653636) max := i64(3246727724653636)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64n(max) value := rng.i64n(max)
@ -225,7 +226,7 @@ fn test_pcg32_int_in_range() {
min := -4252 min := -4252
max := 1034 max := 1034
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int_in_range(min, max) value := rng.int_in_range(min, max)
@ -239,7 +240,7 @@ fn test_pcg32_i64_in_range() {
min := i64(-24095) min := i64(-24095)
max := i64(324058) max := i64(324058)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64_in_range(min, max) value := rng.i64_in_range(min, max)
@ -251,7 +252,7 @@ fn test_pcg32_i64_in_range() {
fn test_pcg32_f32() { fn test_pcg32_f32() {
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32()
@ -263,7 +264,7 @@ fn test_pcg32_f32() {
fn test_pcg32_f64() { fn test_pcg32_f64() {
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64()
@ -276,10 +277,10 @@ fn test_pcg32_f64() {
fn test_pcg32_f32n() { fn test_pcg32_f32n() {
max := f32(357.0) max := f32(357.0)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -289,10 +290,10 @@ fn test_pcg32_f32n() {
fn test_pcg32_f64n() { fn test_pcg32_f64n() {
max := 1.52e6 max := 1.52e6
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -303,10 +304,10 @@ fn test_pcg32_f32_in_range() {
min := f32(-24.0) min := f32(-24.0)
max := f32(125.0) max := f32(125.0)
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -317,10 +318,10 @@ fn test_pcg32_f64_in_range() {
min := -548.7 min := -548.7
max := 5015.2 max := 5015.2
for seed in seeds { for seed in seeds {
mut rng := rand.PCG32RNG{} mut rng := pcg32.PCG32RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }

View File

@ -3,72 +3,128 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module rand
// TODO: Remove these functions once done: import rand.util
// 1. C.rand() import rand.wyrand
// 2. seed()
// 3. next()
// 4. rand_r()
// fn C.rand() int
pub fn seed(s int) {
C.srand(s)
}
pub fn next(max int) int {
return C.rand() % max
}
// rand_r returns a pseudo-random number;
// writes a result value to the seed argument.
pub fn rand_r(seed &int) int {
ns := *seed * 1103515245 + 12345
unsafe {
(*seed) = ns
}
return ns & 0x7fffffff
}
// Configuration struct for creating a new instance of the default RNG.
pub struct PRNGConfigStruct { pub struct PRNGConfigStruct {
seed []u32 = time_seed_array(2) seed []u32 = util.time_seed_array(2)
} }
pub fn new_default(config PRNGConfigStruct) &WyRandRNG { __global default_rng &wyrand.WyRandRNG
rng := &WyRandRNG{} fn init() {
default_rng = new_default({})
}
// new_default returns a new instance of the default RNG. If the seed is not provided, the current time will be used to seed the instance.
pub fn new_default(config PRNGConfigStruct) &wyrand.WyRandRNG {
rng := &wyrand.WyRandRNG{}
rng.seed(config.seed) rng.seed(config.seed)
return rng return rng
} }
// rand_f32 return a random f32 between 0 and max // seed sets the given array of `u32` values as the seed for the `default_rng`.
[deprecated] pub fn seed(seed []u32) {
pub fn rand_f32(max f32) f32 { default_rng.seed(seed)
return rand_uniform_f32() * max
} }
// rand_f32 return a random f32 in range min and max // u32() returns a uniformly distributed u32 in _[0, 2<sup>32</sup>)_
[deprecated] pub fn u32() u32 {
pub fn rand_f32_in_range(min, max f32) f32 { return default_rng.u32()
return min + rand_uniform_f32() * (max - min)
} }
// rand_f64 return a random f64 between 0 (inclusive) and max (exclusive) // u64() returns a uniformly distributed u64 in _[0, 2<sup>64</sup>)_
[deprecated] pub fn u64() u64 {
pub fn rand_f64(max f64) f64 { return default_rng.u64()
return rand_uniform_f64() * max
} }
// rand_f64 return a random f64 in range min (inclusive) and max (exclusive) // u32n(max) returns a uniformly distributed pseudorandom 32-bit signed positive u32 in _[0, max)_
[deprecated] pub fn u32n(max u32) u32 {
pub fn rand_f64_in_range(min, max f64) f64 { return default_rng.u32n(max)
return min + rand_uniform_f64() * (max - min)
} }
// rand_uniform_f32 returns a uniformly distributed f32 in the range 0 (inclusive) and 1 (exclusive) // u64n(max) returns a uniformly distributed pseudorandom 64-bit signed positive u64 in _[0, max)_
[deprecated] pub fn u64n(max u64) u64 {
pub fn rand_uniform_f32() f32 { return default_rng.u64n(max)
return f32(C.rand()) / f32(C.RAND_MAX)
} }
// rand_uniform_f64 returns a uniformly distributed f64 in the range 0 (inclusive) and 1 (exclusive) // u32_in_range(min, max) returns a uniformly distributed pseudorandom 32-bit unsigned u32 in _[min, max)_
[deprecated] pub fn u32_in_range(min, max u32) u32 {
pub fn rand_uniform_f64() f64 { return default_rng.u32_in_range(min, max)
return f64(C.rand()) / f64(C.RAND_MAX) }
// u64_in_range(min, max) returns a uniformly distributed pseudorandom 64-bit unsigned u64 in _[min, max)_
pub fn u64_in_range(min, max u64) u64 {
return default_rng.u64_in_range(min, max)
}
// int() returns a uniformly distributed pseudorandom 32-bit signed (possibly negative) int
pub fn int() int {
return default_rng.int()
}
// intn(max) returns a uniformly distributed pseudorandom 32-bit signed positive int in _[0, max)_
pub fn intn(max int) int {
return default_rng.intn(max)
}
// int_in_range(min, max) returns a uniformly distributed pseudorandom
// 32-bit signed int in [min, max). Both min and max can be negative, but we must have _min < max_.
pub fn int_in_range(min, max int) int {
return default_rng.int_in_range(min, max)
}
// int31() returns a uniformly distributed pseudorandom 31-bit signed positive int
pub fn int31() int {
return default_rng.int31()
}
// i64() returns a uniformly distributed pseudorandom 64-bit signed (possibly negative) i64
pub fn i64() i64 {
return default_rng.i64()
}
// i64n(max) returns a uniformly distributed pseudorandom 64-bit signed positive i64 in _[0, max)_
pub fn i64n(max i64) i64 {
return default_rng.i64n(max)
}
// i64_in_range(min, max) returns a uniformly distributed pseudorandom 64-bit signed int in _[min, max)_
pub fn i64_in_range(min, max i64) i64 {
return default_rng.i64_in_range(min, max)
}
// int63() returns a uniformly distributed pseudorandom 63-bit signed positive int
pub fn int63() i64 {
return default_rng.int63()
}
// f32() returns a uniformly distributed 32-bit floating point in _[0, 1)_
pub fn f32() f32 {
return default_rng.f32()
}
// f64() returns a uniformly distributed 64-bit floating point in _[0, 1)_
pub fn f64() f64 {
return default_rng.f64()
}
// f32n() returns a uniformly distributed 32-bit floating point in _[0, max)_
pub fn f32n(max f32) f32 {
return default_rng.f32n(max)
}
// f64n() returns a uniformly distributed 64-bit floating point in _[0, max)_
pub fn f64n(max f64) f64 {
return default_rng.f64n(max)
}
// f32_in_range(min, max) returns a uniformly distributed 32-bit floating point in _[min, max)_
pub fn f32_in_range(min, max f32) f32 {
return default_rng.f32_in_range(min, max)
}
// f64_in_range(min, max) returns a uniformly distributed 64-bit floating point in _[min, max)_
pub fn f64_in_range(min, max f64) f64 {
return default_rng.f64_in_range(min, max)
} }

View File

@ -1,56 +1,177 @@
import rand import rand
import math
const ( const (
rnd_count = 40 rnd_count = 40
seeds = [42, 256] seeds = [[u32(42), 0], [u32(256), 0]]
) )
fn get_n_random_ints(seed_data []u32, n int) []int {
mut values := []int{cap: n}
rand.seed(seed_data)
for _ in 0 .. n {
values << rand.intn(n)
}
return values
}
fn test_rand_reproducibility() { fn test_rand_reproducibility() {
for seed in seeds { for seed in seeds {
mut randoms1 := gen_randoms(seed) array1 := get_n_random_ints(seed, 1000)
mut randoms2 := gen_randoms(seed) array2 := get_n_random_ints(seed, 1000)
assert_randoms_equal(randoms1, randoms2) assert array1.len == array2.len
assert array1 == array2
} }
} }
fn test_rand_r_reproducibility() { fn test_rand_u32n() {
for seed in seeds { max := u32(16384)
mut randoms1 := gen_randoms_r(seed)
mut randoms2 := gen_randoms_r(seed)
assert_randoms_equal(randoms1, randoms2)
}
}
fn test_rand_r_seed_update() {
seed := 10
for _ in 0 .. rnd_count { for _ in 0 .. rnd_count {
prev_seed := seed value := rand.u32n(max)
_ = rand.rand_r(&seed) assert value >= 0
assert prev_seed != seed assert value < max
} }
} }
fn gen_randoms(seed int) []int { fn test_rand_u64n() {
mut randoms := [0].repeat(rnd_count) max := u64(379091181005)
rand.seed(seed) for _ in 0 .. rnd_count {
for i in 0 .. rnd_count { value := rand.u64n(max)
randoms[i] = rand.next(100) assert value >= 0
} assert value < max
return randoms
}
fn gen_randoms_r(seed int) []int {
mut randoms := [0].repeat(rnd_count)
for i in 0 .. rnd_count {
randoms[i] = rand.rand_r(&seed)
}
return randoms
}
fn assert_randoms_equal(r1, r2 []int) {
for i in 0 .. rnd_count {
assert r1[i] == r2[i]
} }
} }
fn test_rand_u32_in_range() {
max := u32(484468466)
min := u32(316846)
for _ in 0 .. rnd_count {
value := rand.u32_in_range(min, max)
assert value >= min
assert value < max
}
}
fn test_rand_u64_in_range() {
max := u64(216468454685163)
min := u64(6848646868)
for _ in 0 .. rnd_count {
value := rand.u64_in_range(min, max)
assert value >= min
assert value < max
}
}
fn test_rand_intn() {
max := 2525642
for _ in 0 .. rnd_count {
value := rand.intn(max)
assert value >= 0
assert value < max
}
}
fn test_rand_i64n() {
max := i64(3246727724653636)
for _ in 0 .. rnd_count {
value := rand.i64n(max)
assert value >= 0
assert value < max
}
}
fn test_rand_int_in_range() {
min := -4252
max := 23054962
for _ in 0 .. rnd_count {
value := rand.int_in_range(min, max)
assert value >= min
assert value < max
}
}
fn test_rand_i64_in_range() {
min := i64(-24095)
max := i64(324058)
for _ in 0 .. rnd_count {
value := rand.i64_in_range(min, max)
assert value >= min
assert value < max
}
}
fn test_rand_int31() {
max_u31 := 0x7FFFFFFF
sign_mask := 0x80000000
for _ in 0 .. rnd_count {
value := rand.int31()
assert value >= 0
assert value <= max_u31
// This statement ensures that the sign bit is zero
assert (value & sign_mask) == 0
}
}
fn test_rand_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000)
for _ in 0 .. rnd_count {
value := rand.int63()
assert value >= 0
assert value <= max_u63
assert (value & sign_mask) == 0
}
}
fn test_rand_f32() {
for _ in 0 .. rnd_count {
value := rand.f32()
assert value >= 0.0
assert value < 1.0
}
}
fn test_rand_f64() {
for _ in 0 .. rnd_count {
value := rand.f64()
assert value >= 0.0
assert value < 1.0
}
}
fn test_rand_f32n() {
max := f32(357.0)
for _ in 0 .. rnd_count {
value := rand.f32n(max)
assert value >= 0.0
assert value < max
}
}
fn test_rand_f64n() {
max := f64(1.52e6)
for _ in 0 .. rnd_count {
value := rand.f64n(max)
assert value >= 0.0
assert value < max
}
}
fn test_rand_f32_in_range() {
min := f32(-24.0)
max := f32(125.0)
for _ in 0 .. rnd_count {
value := rand.f32_in_range(min, max)
assert value >= min
assert value < max
}
}
fn test_rand_f64_in_range() {
min := f64(-548.7)
max := f64(5015.2)
for _ in 0 .. rnd_count {
value := rand.f64_in_range(min, max)
assert value >= min
assert value < max
}
}

View File

@ -1,12 +1,14 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module splitmix64
import rand.util
// Ported from http://xoshiro.di.unimi.it/splitmix64.c // Ported from http://xoshiro.di.unimi.it/splitmix64.c
pub struct SplitMix64RNG { pub struct SplitMix64RNG {
mut: mut:
state u64 = time_seed_64() state u64 = util.time_seed_64()
has_extra bool = false has_extra bool = false
extra u32 extra u32
} }
@ -30,7 +32,7 @@ pub fn (mut rng SplitMix64RNG) u32() u32 {
return rng.extra return rng.extra
} }
full_value := rng.u64() full_value := rng.u64()
lower := u32(full_value & lower_mask) lower := u32(full_value & util.lower_mask)
upper := u32(full_value >> 32) upper := u32(full_value >> 32)
rng.extra = upper rng.extra = upper
rng.has_extra = true rng.has_extra = true
@ -119,13 +121,13 @@ pub fn (mut rng SplitMix64RNG) i64() i64 {
// rng.int31() returns a pseudorandom 31-bit int which is non-negative // rng.int31() returns a pseudorandom 31-bit int which is non-negative
[inline] [inline]
pub fn (mut rng SplitMix64RNG) int31() int { pub fn (mut rng SplitMix64RNG) int31() int {
return int(rng.u32() & u31_mask) // Set the 32nd bit to 0. return int(rng.u32() & util.u31_mask) // Set the 32nd bit to 0.
} }
// rng.int63() returns a pseudorandom 63-bit int which is non-negative // rng.int63() returns a pseudorandom 63-bit int which is non-negative
[inline] [inline]
pub fn (mut rng SplitMix64RNG) int63() i64 { pub fn (mut rng SplitMix64RNG) int63() i64 {
return i64(rng.u64() & u63_mask) // Set the 64th bit to 0. return i64(rng.u64() & util.u63_mask) // Set the 64th bit to 0.
} }
// rng.intn(max) returns a pseudorandom int that lies in [0, max) // rng.intn(max) returns a pseudorandom int that lies in [0, max)
@ -172,13 +174,13 @@ pub fn (mut rng SplitMix64RNG) i64_in_range(min, max i64) i64 {
// rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng SplitMix64RNG) f32() f32 { pub fn (mut rng SplitMix64RNG) f32() f32 {
return f32(rng.u32()) / max_u32_as_f32 return f32(rng.u32()) / util.max_u32_as_f32
} }
// rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng SplitMix64RNG) f64() f64 { pub fn (mut rng SplitMix64RNG) f64() f64 {
return f64(rng.u64()) / max_u64_as_f64 return f64(rng.u64()) / util.max_u64_as_f64
} }
// rng.f32n() returns a pseudorandom f32 value in [0, max) // rng.f32n() returns a pseudorandom f32 value in [0, max)

View File

@ -1,5 +1,6 @@
import rand
import math import math
import splitmix64
import rand.util
const ( const (
range_limit = 40 range_limit = 40
@ -16,7 +17,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(0)].repeat(20) mut randoms := [u64(0)].repeat(20)
mut rnd := rand.SplitMix64RNG{} mut rnd := splitmix64.SplitMix64RNG{}
rnd.seed(seed_data) rnd.seed(seed_data)
for i in 0 .. 20 { for i in 0 .. 20 {
randoms[i] = rnd.u64n(bound_u64) randoms[i] = rnd.u64n(bound_u64)
@ -25,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
} }
fn test_splitmix64_reproducibility() { fn test_splitmix64_reproducibility() {
seed_data := rand.time_seed_array(2) seed_data := util.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
@ -51,7 +52,7 @@ fn test_splitmix64_variability() {
// at fault, try changing the seed values. Repeated values are // at fault, try changing the seed values. Repeated values are
// improbable but not impossible. // improbable but not impossible.
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
mut values := []u64{cap: value_count} mut values := []u64{cap: value_count}
for i in 0 .. value_count { for i in 0 .. value_count {
@ -63,7 +64,7 @@ fn test_splitmix64_variability() {
} }
} }
fn check_uniformity_u64(mut rng rand.SplitMix64RNG, range u64) { fn check_uniformity_u64(mut rng splitmix64.SplitMix64RNG, range u64) {
range_f64 := f64(range) range_f64 := f64(range)
expected_mean := range_f64 / 2.0 expected_mean := range_f64 / 2.0
mut variance := 0.0 mut variance := 0.0
@ -81,7 +82,7 @@ fn check_uniformity_u64(mut rng rand.SplitMix64RNG, range u64) {
fn test_splitmix64_uniformity_u64() { fn test_splitmix64_uniformity_u64() {
ranges := [14019545, 80240, 130] ranges := [14019545, 80240, 130]
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for range in ranges { for range in ranges {
check_uniformity_u64(mut rng, u64(range)) check_uniformity_u64(mut rng, u64(range))
@ -89,7 +90,7 @@ fn test_splitmix64_uniformity_u64() {
} }
} }
fn check_uniformity_f64(mut rng rand.SplitMix64RNG) { fn check_uniformity_f64(mut rng splitmix64.SplitMix64RNG) {
expected_mean := 0.5 expected_mean := 0.5
mut variance := 0.0 mut variance := 0.0
for _ in 0 .. sample_size { for _ in 0 .. sample_size {
@ -106,19 +107,19 @@ fn check_uniformity_f64(mut rng rand.SplitMix64RNG) {
fn test_splitmix64_uniformity_f64() { fn test_splitmix64_uniformity_f64() {
// The f64 version // The f64 version
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
check_uniformity_f64(mut rng) check_uniformity_f64(mut rng)
} }
} }
fn test_splitmix64_u32n() { fn test_splitmix64_u32n() {
max := 16384 max := u32(16384)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32n(u32(max)) value := rng.u32n(max)
assert value >= 0 assert value >= 0
assert value < max assert value < max
} }
@ -128,7 +129,7 @@ fn test_splitmix64_u32n() {
fn test_splitmix64_u64n() { fn test_splitmix64_u64n() {
max := u64(379091181005) max := u64(379091181005)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64n(max) value := rng.u64n(max)
@ -139,13 +140,13 @@ fn test_splitmix64_u64n() {
} }
fn test_splitmix64_u32_in_range() { fn test_splitmix64_u32_in_range() {
max := 484468466 max := u32(484468466)
min := 316846 min := u32(316846)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32_in_range(u32(min), u32(max)) value := rng.u32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -156,7 +157,7 @@ fn test_splitmix64_u64_in_range() {
max := u64(216468454685163) max := u64(216468454685163)
min := u64(6848646868) min := u64(6848646868)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64_in_range(min, max) value := rng.u64_in_range(min, max)
@ -170,7 +171,7 @@ fn test_splitmix64_int31() {
max_u31 := 0x7FFFFFFF max_u31 := 0x7FFFFFFF
sign_mask := 0x80000000 sign_mask := 0x80000000
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int31() value := rng.int31()
@ -186,7 +187,7 @@ fn test_splitmix64_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF) max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000) sign_mask := i64(0x8000000000000000)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int63() value := rng.int63()
@ -197,10 +198,10 @@ fn test_splitmix64_int63() {
} }
} }
fn test_splimix64_intn() { fn test_splitmix64_intn() {
max := 2525642 max := 2525642
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.intn(max) value := rng.intn(max)
@ -210,10 +211,10 @@ fn test_splimix64_intn() {
} }
} }
fn test_splimix64_i64n() { fn test_splitmix64_i64n() {
max := i64(3246727724653636) max := i64(3246727724653636)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64n(max) value := rng.i64n(max)
@ -223,11 +224,11 @@ fn test_splimix64_i64n() {
} }
} }
fn test_splimix64_int_in_range() { fn test_splitmix64_int_in_range() {
min := -4252 min := -4252
max := 230549862 max := 230549862
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int_in_range(min, max) value := rng.int_in_range(min, max)
@ -237,11 +238,11 @@ fn test_splimix64_int_in_range() {
} }
} }
fn test_splimix64_i64_in_range() { fn test_splitmix64_i64_in_range() {
min := i64(-24095) min := i64(-24095)
max := i64(324058) max := i64(324058)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64_in_range(min, max) value := rng.i64_in_range(min, max)
@ -253,7 +254,7 @@ fn test_splimix64_i64_in_range() {
fn test_splitmix64_f32() { fn test_splitmix64_f32() {
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32()
@ -265,7 +266,7 @@ fn test_splitmix64_f32() {
fn test_splitmix64_f64() { fn test_splitmix64_f64() {
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64()
@ -278,10 +279,10 @@ fn test_splitmix64_f64() {
fn test_splitmix64_f32n() { fn test_splitmix64_f32n() {
max := f32(357.0) max := f32(357.0)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -291,10 +292,10 @@ fn test_splitmix64_f32n() {
fn test_splitmix64_f64n() { fn test_splitmix64_f64n() {
max := 1.52e6 max := 1.52e6
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -305,10 +306,10 @@ fn test_splitmix64_f32_in_range() {
min := f32(-24.0) min := f32(-24.0)
max := f32(125.0) max := f32(125.0)
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -319,10 +320,10 @@ fn test_splitmix64_f64_in_range() {
min := -548.7 min := -548.7
max := 5015.2 max := 5015.2
for seed in seeds { for seed in seeds {
mut rng := rand.SplitMix64RNG{} mut rng := splitmix64.SplitMix64RNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }

View File

@ -1,9 +1,10 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module sys
import math.bits import math.bits
import rand.util
// Implementation note: // Implementation note:
// ==================== // ====================
@ -27,20 +28,6 @@ fn calculate_iterations_for(bits int) int {
return base + extra return base + extra
} }
// Size constants to avoid importing the entire math module
const (
max_u32 = 0xFFFFFFFF
max_u64 = 0xFFFFFFFFFFFFFFFF
max_u32_as_f32 = f32(max_u32)
max_u64_as_f64 = f64(max_u64)
)
// Masks for fast modular division
const (
u31_mask = u32(0x7FFFFFFF)
u63_mask = u64(0x7FFFFFFFFFFFFFFF)
)
// C.rand returns a pseudorandom integer from 0 (inclusive) to C.RAND_MAX (exclusive) // C.rand returns a pseudorandom integer from 0 (inclusive) to C.RAND_MAX (exclusive)
fn C.rand() int fn C.rand() int
@ -49,7 +36,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 = time_seed_32() seed u32 = util.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.
@ -188,13 +175,13 @@ pub fn (r SysRNG) i64() i64 {
// r.int31() returns a pseudorandom 31-bit int which is non-negative // r.int31() returns a pseudorandom 31-bit int which is non-negative
[inline] [inline]
pub fn (r SysRNG) int31() int { pub fn (r SysRNG) int31() int {
return int(r.u32() & u31_mask) // Set the 32nd bit to 0. return int(r.u32() & util.u31_mask) // Set the 32nd bit to 0.
} }
// r.int63() returns a pseudorandom 63-bit int which is non-negative // r.int63() returns a pseudorandom 63-bit int which is non-negative
[inline] [inline]
pub fn (r SysRNG) int63() i64 { pub fn (r SysRNG) int63() i64 {
return i64(r.u64() & u63_mask) // Set the 64th bit to 0. return i64(r.u64() & util.u63_mask) // Set the 64th bit to 0.
} }
// r.intn(max) returns a pseudorandom int that lies in [0, max) // r.intn(max) returns a pseudorandom int that lies in [0, max)
@ -241,13 +228,13 @@ pub fn (r SysRNG) i64_in_range(min, max i64) i64 {
// r.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // r.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (r SysRNG) f32() f32 { pub fn (r SysRNG) f32() f32 {
return f32(r.u32()) / max_u32_as_f32 return f32(r.u32()) / util.max_u32_as_f32
} }
// r.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // r.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (r SysRNG) f64() f64 { pub fn (r SysRNG) f64() f64 {
return f64(r.u64()) / max_u64_as_f64 return f64(r.u64()) / util.max_u64_as_f64
} }
// r.f32n() returns a pseudorandom f32 value in [0, max) // r.f32n() returns a pseudorandom f32 value in [0, max)

View File

@ -1,7 +1,7 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module sys
// Until there's a portable, JS has a seeded way to produce random numbers // Until there's a portable, JS has a seeded way to produce random numbers
// and not just Math.random(), use any of the existing implementations // and not just Math.random(), use any of the existing implementations

View File

@ -1,5 +1,5 @@
import rand
import math import math
import sys
const ( const (
range_limit = 40 range_limit = 40
@ -13,7 +13,7 @@ const (
inv_sqrt_12 = 1.0 / math.sqrt(12) inv_sqrt_12 = 1.0 / math.sqrt(12)
) )
fn get_n_randoms(n int, r rand.SysRNG) []int { fn get_n_randoms(n int, r sys.SysRNG) []int {
mut ints := []int{cap: n} mut ints := []int{cap: n}
for _ in 0 .. n { for _ in 0 .. n {
ints << r.int() ints << r.int()
@ -28,8 +28,8 @@ fn test_sys_rng_reproducibility() {
// seed for another batch of data. // seed for another batch of data.
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut r1 := rand.SysRNG{} mut r1 := sys.SysRNG{}
mut r2 := rand.SysRNG{} mut r2 := sys.SysRNG{}
r1.seed(seed_data) r1.seed(seed_data)
ints1 := get_n_randoms(value_count, r1) ints1 := get_n_randoms(value_count, r1)
r2.seed(seed_data) r2.seed(seed_data)
@ -55,7 +55,7 @@ fn test_sys_rng_variability() {
// improbable but not impossible. // improbable but not impossible.
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
mut values := []u64{cap: value_count} mut values := []u64{cap: value_count}
for i in 0 .. value_count { for i in 0 .. value_count {
@ -67,7 +67,7 @@ fn test_sys_rng_variability() {
} }
} }
fn check_uniformity_u64(rng rand.SysRNG, range u64) { fn check_uniformity_u64(rng sys.SysRNG, range u64) {
range_f64 := f64(range) range_f64 := f64(range)
expected_mean := range_f64 / 2.0 expected_mean := range_f64 / 2.0
mut variance := 0.0 mut variance := 0.0
@ -88,7 +88,7 @@ fn test_sys_rng_uniformity_u64() {
ranges := [14019545, 80240, 130] ranges := [14019545, 80240, 130]
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for range in ranges { for range in ranges {
check_uniformity_u64(rng, u64(range)) check_uniformity_u64(rng, u64(range))
@ -96,7 +96,7 @@ fn test_sys_rng_uniformity_u64() {
} }
} }
fn check_uniformity_f64(rng rand.SysRNG) { fn check_uniformity_f64(rng sys.SysRNG) {
expected_mean := 0.5 expected_mean := 0.5
mut variance := 0.0 mut variance := 0.0
for _ in 0 .. sample_size { for _ in 0 .. sample_size {
@ -114,20 +114,20 @@ fn test_sys_rng_uniformity_f64() {
// The f64 version // The f64 version
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
check_uniformity_f64(rng) check_uniformity_f64(rng)
} }
} }
fn test_sys_rng_u32n() { fn test_sys_rng_u32n() {
max := 16384 max := u32(16384)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32n(u32(max)) value := rng.u32n(max)
assert value >= 0 assert value >= 0
assert value < max assert value < max
} }
@ -138,7 +138,7 @@ fn test_sys_rng_u64n() {
max := u64(379091181005) max := u64(379091181005)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64n(max) value := rng.u64n(max)
@ -149,14 +149,14 @@ fn test_sys_rng_u64n() {
} }
fn test_sys_rng_u32_in_range() { fn test_sys_rng_u32_in_range() {
max := 484468466 max := u32(484468466)
min := 316846 min := u32(316846)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32_in_range(u32(min), u32(max)) value := rng.u32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -168,7 +168,7 @@ fn test_sys_rng_u64_in_range() {
min := u64(6848646868) min := u64(6848646868)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64_in_range(min, max) value := rng.u64_in_range(min, max)
@ -182,7 +182,7 @@ fn test_sys_rng_intn() {
max := 2525642 max := 2525642
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.intn(max) value := rng.intn(max)
@ -196,7 +196,7 @@ fn test_sys_rng_i64n() {
max := i64(3246727724653636) max := i64(3246727724653636)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64n(max) value := rng.i64n(max)
@ -211,7 +211,7 @@ fn test_sys_rng_int_in_range() {
max := 23054962 max := 23054962
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int_in_range(min, max) value := rng.int_in_range(min, max)
@ -226,7 +226,7 @@ fn test_sys_rng_i64_in_range() {
max := i64(324058) max := i64(324058)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64_in_range(min, max) value := rng.i64_in_range(min, max)
@ -241,7 +241,7 @@ fn test_sys_rng_int31() {
sign_mask := 0x80000000 sign_mask := 0x80000000
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int31() value := rng.int31()
@ -258,7 +258,7 @@ fn test_sys_rng_int63() {
sign_mask := i64(0x8000000000000000) sign_mask := i64(0x8000000000000000)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int63() value := rng.int63()
@ -272,7 +272,7 @@ fn test_sys_rng_int63() {
fn test_sys_rng_f32() { fn test_sys_rng_f32() {
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32()
@ -285,7 +285,7 @@ fn test_sys_rng_f32() {
fn test_sys_rng_f64() { fn test_sys_rng_f64() {
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64()
@ -299,10 +299,10 @@ fn test_sys_rng_f32n() {
max := f32(357.0) max := f32(357.0)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -313,10 +313,10 @@ fn test_sys_rng_f64n() {
max := 1.52e6 max := 1.52e6
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -328,10 +328,10 @@ fn test_sys_rng_f32_in_range() {
max := f32(125.0) max := f32(125.0)
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -343,10 +343,10 @@ fn test_sys_rng_f64_in_range() {
max := 5015.2 max := 5015.2
for seed in seeds { for seed in seeds {
seed_data := [seed] seed_data := [seed]
mut rng := rand.SysRNG{} mut rng := sys.SysRNG{}
rng.seed(seed_data) rng.seed(seed_data)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }

View File

@ -1,13 +1,19 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module util
import time import time
// Commonly used constants across RNGs // Commonly used constants across RNGs
const ( pub const (
lower_mask = u64(0x00000000ffffffff) lower_mask = u64(0x00000000FFFFFFFF)
max_u32 = 0xFFFFFFFF
max_u64 = 0xFFFFFFFFFFFFFFFF
max_u32_as_f32 = f32(max_u32) + 1
max_u64_as_f64 = f64(max_u64) + 1
u31_mask = u32(0x7FFFFFFF)
u63_mask = u64(0x7FFFFFFFFFFFFFFF)
) )
// Constants taken from Numerical Recipes // Constants taken from Numerical Recipes
@ -16,7 +22,7 @@ fn nr_next(prev u32) u32 {
return prev * 1664525 + 1013904223 return prev * 1664525 + 1013904223
} }
// utility function that return the required number of u32s generated from system time // time_seed_array is a utility function that returns the required number of u32s generated from system time
[inline] [inline]
pub fn time_seed_array(count int) []u32 { pub fn time_seed_array(count int) []u32 {
mut seed := u32(time.now().unix_time()) mut seed := u32(time.now().unix_time())
@ -28,13 +34,15 @@ pub fn time_seed_array(count int) []u32 {
return seed_data return seed_data
} }
// time_seed_32 returns a 32-bit seed geenrated from system time
[inline] [inline]
fn time_seed_32() u32 { pub fn time_seed_32() u32 {
return time_seed_array(1)[0] return time_seed_array(1)[0]
} }
// time_seed_64 returns a 64-bit seed geenrated from system time
[inline] [inline]
fn time_seed_64() u64 { pub fn time_seed_64() u64 {
seed_data := time_seed_array(2) seed_data := time_seed_array(2)
lower := u64(seed_data[0]) lower := u64(seed_data[0])
upper := u64(seed_data[1]) upper := u64(seed_data[1])

View File

@ -1,9 +1,10 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module wyrand
import math.bits import math.bits
import rand.util
import hash.wyhash import hash.wyhash
// Redefinition of some constants that we will need for pseudorandom number generation // Redefinition of some constants that we will need for pseudorandom number generation
@ -15,7 +16,7 @@ const (
// RNG based on the WyHash hashing algorithm // RNG based on the WyHash hashing algorithm
pub struct WyRandRNG { pub struct WyRandRNG {
mut: mut:
state u64 = time_seed_64() state u64 = util.time_seed_64()
has_extra bool = false has_extra bool = false
extra u32 extra u32
} }
@ -30,7 +31,6 @@ pub fn (mut rng WyRandRNG) seed(seed_data []u32) {
rng.has_extra = false rng.has_extra = false
} }
// rng.u32() updates the PRNG state and returns the next pseudorandom u32 // rng.u32() updates the PRNG state and returns the next pseudorandom u32
[inline] [inline]
pub fn (mut rng WyRandRNG) u32() u32 { pub fn (mut rng WyRandRNG) u32() u32 {
@ -39,7 +39,7 @@ pub fn (mut rng WyRandRNG) u32() u32 {
return rng.extra return rng.extra
} }
full_value := rng.u64() full_value := rng.u64()
lower := u32(full_value & lower_mask) lower := u32(full_value & util.lower_mask)
upper := u32(full_value >> 32) upper := u32(full_value >> 32)
rng.extra = upper rng.extra = upper
rng.has_extra = true rng.has_extra = true
@ -148,13 +148,13 @@ pub fn (mut rng WyRandRNG) i64() i64 {
// rng.int31() returns a pseudorandom 31-bit int which is non-negative // rng.int31() returns a pseudorandom 31-bit int which is non-negative
[inline] [inline]
pub fn (mut rng WyRandRNG) int31() int { pub fn (mut rng WyRandRNG) int31() int {
return int(rng.u32() & u31_mask) // Set the 32nd bit to 0. return int(rng.u32() & util.u31_mask) // Set the 32nd bit to 0.
} }
// rng.int63() returns a pseudorandom 63-bit int which is non-negative // rng.int63() returns a pseudorandom 63-bit int which is non-negative
[inline] [inline]
pub fn (mut rng WyRandRNG) int63() i64 { pub fn (mut rng WyRandRNG) int63() i64 {
return i64(rng.u64() & u63_mask) // Set the 64th bit to 0. return i64(rng.u64() & util.u63_mask) // Set the 64th bit to 0.
} }
// rng.intn(max) returns a pseudorandom int that lies in [0, max) // rng.intn(max) returns a pseudorandom int that lies in [0, max)
@ -201,13 +201,13 @@ pub fn (mut rng WyRandRNG) i64_in_range(min, max i64) i64 {
// rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f32() returns a pseudorandom f32 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng WyRandRNG) f32() f32 { pub fn (mut rng WyRandRNG) f32() f32 {
return f32(rng.u32()) / max_u32_as_f32 return f32(rng.u32()) / util.max_u32_as_f32
} }
// rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1) // rng.f64() returns a pseudorandom f64 value between 0.0 (inclusive) and 1.0 (exclusive) i.e [0, 1)
[inline] [inline]
pub fn (mut rng WyRandRNG) f64() f64 { pub fn (mut rng WyRandRNG) f64() f64 {
return f64(rng.u64()) / max_u64_as_f64 return f64(rng.u64()) / util.max_u64_as_f64
} }
// rng.f32n() returns a pseudorandom f32 value in [0, max) // rng.f32n() returns a pseudorandom f32 value in [0, max)

View File

@ -1,5 +1,6 @@
import rand
import math import math
import rand.util
import wyrand
const ( const (
range_limit = 40 range_limit = 40
@ -16,7 +17,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(0)].repeat(20) mut randoms := [u64(0)].repeat(20)
mut rnd := rand.WyRandRNG{} mut rnd := wyrand.WyRandRNG{}
rnd.seed(seed_data) rnd.seed(seed_data)
for i in 0 .. 20 { for i in 0 .. 20 {
randoms[i] = rnd.u64n(bound_u64) randoms[i] = rnd.u64n(bound_u64)
@ -25,7 +26,7 @@ fn gen_randoms(seed_data []u32, bound int) []u64 {
} }
fn test_wyrand_reproducibility() { fn test_wyrand_reproducibility() {
seed_data := rand.time_seed_array(2) seed_data := util.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
@ -51,7 +52,7 @@ fn test_wyrand_variability() {
// at fault, try changing the seed values. Repeated values are // at fault, try changing the seed values. Repeated values are
// improbable but not impossible. // improbable but not impossible.
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
mut values := []u64{cap: value_count} mut values := []u64{cap: value_count}
for i in 0 .. value_count { for i in 0 .. value_count {
@ -63,7 +64,7 @@ fn test_wyrand_variability() {
} }
} }
fn check_uniformity_u64(mut rng rand.WyRandRNG, range u64) { fn check_uniformity_u64(mut rng wyrand.WyRandRNG, range u64) {
range_f64 := f64(range) range_f64 := f64(range)
expected_mean := range_f64 / 2.0 expected_mean := range_f64 / 2.0
mut variance := 0.0 mut variance := 0.0
@ -81,7 +82,7 @@ fn check_uniformity_u64(mut rng rand.WyRandRNG, range u64) {
fn test_wyrand_uniformity_u64() { fn test_wyrand_uniformity_u64() {
ranges := [14019545, 80240, 130] ranges := [14019545, 80240, 130]
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for range in ranges { for range in ranges {
check_uniformity_u64(mut rng, u64(range)) check_uniformity_u64(mut rng, u64(range))
@ -89,7 +90,7 @@ fn test_wyrand_uniformity_u64() {
} }
} }
fn check_uniformity_f64(mut rng rand.WyRandRNG) { fn check_uniformity_f64(mut rng wyrand.WyRandRNG) {
expected_mean := 0.5 expected_mean := 0.5
mut variance := 0.0 mut variance := 0.0
for _ in 0 .. sample_size { for _ in 0 .. sample_size {
@ -106,19 +107,19 @@ fn check_uniformity_f64(mut rng rand.WyRandRNG) {
fn test_wyrand_uniformity_f64() { fn test_wyrand_uniformity_f64() {
// The f64 version // The f64 version
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
check_uniformity_f64(mut rng) check_uniformity_f64(mut rng)
} }
} }
fn test_wyrand_u32n() { fn test_wyrand_u32n() {
max := 16384 max := u32(16384)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32n(u32(max)) value := rng.u32n(max)
assert value >= 0 assert value >= 0
assert value < max assert value < max
} }
@ -128,7 +129,7 @@ fn test_wyrand_u32n() {
fn test_wyrand_u64n() { fn test_wyrand_u64n() {
max := u64(379091181005) max := u64(379091181005)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64n(max) value := rng.u64n(max)
@ -139,13 +140,13 @@ fn test_wyrand_u64n() {
} }
fn test_wyrand_u32_in_range() { fn test_wyrand_u32_in_range() {
max := 484468466 max := u32(484468466)
min := 316846 min := u32(316846)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u32_in_range(u32(min), u32(max)) value := rng.u32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -156,7 +157,7 @@ fn test_wyrand_u64_in_range() {
max := u64(216468454685163) max := u64(216468454685163)
min := u64(6848646868) min := u64(6848646868)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.u64_in_range(min, max) value := rng.u64_in_range(min, max)
@ -170,7 +171,7 @@ fn test_wyrand_int31() {
max_u31 := 0x7FFFFFFF max_u31 := 0x7FFFFFFF
sign_mask := 0x80000000 sign_mask := 0x80000000
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int31() value := rng.int31()
@ -186,7 +187,7 @@ fn test_wyrand_int63() {
max_u63 := i64(0x7FFFFFFFFFFFFFFF) max_u63 := i64(0x7FFFFFFFFFFFFFFF)
sign_mask := i64(0x8000000000000000) sign_mask := i64(0x8000000000000000)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int63() value := rng.int63()
@ -200,7 +201,7 @@ fn test_wyrand_int63() {
fn test_wyrand_intn() { fn test_wyrand_intn() {
max := 2525642 max := 2525642
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.intn(max) value := rng.intn(max)
@ -213,7 +214,7 @@ fn test_wyrand_intn() {
fn test_wyrand_i64n() { fn test_wyrand_i64n() {
max := i64(3246727724653636) max := i64(3246727724653636)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64n(max) value := rng.i64n(max)
@ -227,7 +228,7 @@ fn test_wyrand_int_in_range() {
min := -4252 min := -4252
max := 1034 max := 1034
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.int_in_range(min, max) value := rng.int_in_range(min, max)
@ -241,7 +242,7 @@ fn test_wyrand_i64_in_range() {
min := i64(-24095) min := i64(-24095)
max := i64(324058) max := i64(324058)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.i64_in_range(min, max) value := rng.i64_in_range(min, max)
@ -253,7 +254,7 @@ fn test_wyrand_i64_in_range() {
fn test_wyrand_f32() { fn test_wyrand_f32() {
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32()
@ -265,7 +266,7 @@ fn test_wyrand_f32() {
fn test_wyrand_f64() { fn test_wyrand_f64() {
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64()
@ -278,10 +279,10 @@ fn test_wyrand_f64() {
fn test_wyrand_f32n() { fn test_wyrand_f32n() {
max := f32(357.0) max := f32(357.0)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -291,10 +292,10 @@ fn test_wyrand_f32n() {
fn test_wyrand_f64n() { fn test_wyrand_f64n() {
max := 1.52e6 max := 1.52e6
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64n(max)
assert value >= 0.0 assert value >= 0.0
assert value < max assert value < max
} }
@ -305,10 +306,10 @@ fn test_wyrand_f32_in_range() {
min := f32(-24.0) min := f32(-24.0)
max := f32(125.0) max := f32(125.0)
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f32() value := rng.f32_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }
@ -319,10 +320,10 @@ fn test_wyrand_f64_in_range() {
min := -548.7 min := -548.7
max := 5015.2 max := 5015.2
for seed in seeds { for seed in seeds {
mut rng := rand.WyRandRNG{} mut rng := wyrand.WyRandRNG{}
rng.seed(seed) rng.seed(seed)
for _ in 0 .. range_limit { for _ in 0 .. range_limit {
value := rng.f64() value := rng.f64_in_range(min, max)
assert value >= min assert value >= min
assert value < max assert value < max
} }

View File

@ -8,5 +8,5 @@ const (
) )
// random returns a random time struct in *the past*. // random returns a random time struct in *the past*.
pub fn random() time.Time { pub fn random() time.Time {
return time.unix(rand.next(int(start_time_unix))) return time.unix(int(rand.u64n(start_time_unix)))
} }

View File

@ -3,7 +3,7 @@ import rand
fn test_random() { fn test_random() {
// guarantee CI test stability, by seeding the random number generator with a known seed // guarantee CI test stability, by seeding the random number generator with a known seed
rand.seed(0) rand.seed([u32(0), 0])
t1 := tmisc.random() t1 := tmisc.random()
t2 := tmisc.random() t2 := tmisc.random()
t3 := tmisc.random() t3 := tmisc.random()