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...')
mut bytepile := []byte{}
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{}
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...')
t0 := time.ticks()

View File

@ -22,6 +22,7 @@ const (
]
skip_on_windows = [
'vlib/orm/orm_test.v',
'vlib/net/websocket/ws_test.v',
]
skip_on_non_windows = []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
fn rand_f64() f64 {
x := (C.rand()+1) & 0x3FFF_FFFF
x := (rand.intn(cache_len)+1) & 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()
// tabbed speed-up
r1 := C.rand() & cache_mask
r1 := rand.intn(cache_len) & cache_mask
r2 := rand_f64()
r2s := math.sqrt(r2)
@ -465,9 +465,8 @@ fn main() {
height = os.args[5].int()
}
// init the rand, using the same seed allows to obtain the same result in different runs
// change the seed from 2020 for different results
rand.seed(2020)
// change the seed for a different result
rand.seed([u32(2020), 0])
t1:=time.ticks()

View File

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

View File

@ -2,9 +2,7 @@ import rand
import time
fn main() {
rand.seed(int(time.now().unix))
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() {
g.parse_tetros()
rand.seed(int(time.now().unix))
g.generate_tetro()
g.field = []
// 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() {
g.pos_y = 0
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.get_tetro()
}

View File

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

View File

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

View File

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

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.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module mt19937
import math.bits
import rand.util
/*
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
pub struct MT19937RNG {
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
next_rnd u32 = 0
has_next bool = false

View File

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

View File

@ -1,14 +1,15 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module musl
import math.bits
import rand.util
// Ported from https://git.musl-libc.org/cgit/musl/tree/src/prng/rand_r.c
pub struct MuslRNG {
mut:
state u32 = time_seed_32()
state u32 = util.time_seed_32()
}
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)
[inline]
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)
[inline]
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)

View File

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

View File

@ -1,26 +1,17 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module pcg32
import rand.util
// 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.h
pub struct PCG32RNG {
mut:
state u64 = u64(0x853c49e6748fea9b) ^ time_seed_64()
inc u64 = u64(0xda3e39cb94b95bdb) ^ 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)
state u64 = u64(0x853c49e6748fea9b) ^ util.time_seed_64()
inc u64 = u64(0xda3e39cb94b95bdb) ^ util.time_seed_64()
}
// 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)
[inline]
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)
[inline]
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)

View File

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

View File

@ -3,72 +3,128 @@
// that can be found in the LICENSE file.
module rand
// TODO: Remove these functions once done:
// 1. C.rand()
// 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
}
import rand.util
import rand.wyrand
// Configuration struct for creating a new instance of the default RNG.
pub struct PRNGConfigStruct {
seed []u32 = time_seed_array(2)
seed []u32 = util.time_seed_array(2)
}
pub fn new_default(config PRNGConfigStruct) &WyRandRNG {
rng := &WyRandRNG{}
__global default_rng &wyrand.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)
return rng
}
// rand_f32 return a random f32 between 0 and max
[deprecated]
pub fn rand_f32(max f32) f32 {
return rand_uniform_f32() * max
// seed sets the given array of `u32` values as the seed for the `default_rng`.
pub fn seed(seed []u32) {
default_rng.seed(seed)
}
// rand_f32 return a random f32 in range min and max
[deprecated]
pub fn rand_f32_in_range(min, max f32) f32 {
return min + rand_uniform_f32() * (max - min)
// u32() returns a uniformly distributed u32 in _[0, 2<sup>32</sup>)_
pub fn u32() u32 {
return default_rng.u32()
}
// rand_f64 return a random f64 between 0 (inclusive) and max (exclusive)
[deprecated]
pub fn rand_f64(max f64) f64 {
return rand_uniform_f64() * max
// u64() returns a uniformly distributed u64 in _[0, 2<sup>64</sup>)_
pub fn u64() u64 {
return default_rng.u64()
}
// rand_f64 return a random f64 in range min (inclusive) and max (exclusive)
[deprecated]
pub fn rand_f64_in_range(min, max f64) f64 {
return min + rand_uniform_f64() * (max - min)
// u32n(max) returns a uniformly distributed pseudorandom 32-bit signed positive u32 in _[0, max)_
pub fn u32n(max u32) u32 {
return default_rng.u32n(max)
}
// rand_uniform_f32 returns a uniformly distributed f32 in the range 0 (inclusive) and 1 (exclusive)
[deprecated]
pub fn rand_uniform_f32() f32 {
return f32(C.rand()) / f32(C.RAND_MAX)
// u64n(max) returns a uniformly distributed pseudorandom 64-bit signed positive u64 in _[0, max)_
pub fn u64n(max u64) u64 {
return default_rng.u64n(max)
}
// rand_uniform_f64 returns a uniformly distributed f64 in the range 0 (inclusive) and 1 (exclusive)
[deprecated]
pub fn rand_uniform_f64() f64 {
return f64(C.rand()) / f64(C.RAND_MAX)
// u32_in_range(min, max) returns a uniformly distributed pseudorandom 32-bit unsigned u32 in _[min, max)_
pub fn u32_in_range(min, max u32) u32 {
return default_rng.u32_in_range(min, 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 math
const (
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() {
for seed in seeds {
mut randoms1 := gen_randoms(seed)
mut randoms2 := gen_randoms(seed)
assert_randoms_equal(randoms1, randoms2)
array1 := get_n_random_ints(seed, 1000)
array2 := get_n_random_ints(seed, 1000)
assert array1.len == array2.len
assert array1 == array2
}
}
fn test_rand_r_reproducibility() {
for seed in seeds {
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
fn test_rand_u32n() {
max := u32(16384)
for _ in 0 .. rnd_count {
prev_seed := seed
_ = rand.rand_r(&seed)
assert prev_seed != seed
value := rand.u32n(max)
assert value >= 0
assert value < max
}
}
fn gen_randoms(seed int) []int {
mut randoms := [0].repeat(rnd_count)
rand.seed(seed)
for i in 0 .. rnd_count {
randoms[i] = rand.next(100)
}
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_u64n() {
max := u64(379091181005)
for _ in 0 .. rnd_count {
value := rand.u64n(max)
assert value >= 0
assert value < max
}
}
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.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module splitmix64
import rand.util
// Ported from http://xoshiro.di.unimi.it/splitmix64.c
pub struct SplitMix64RNG {
mut:
state u64 = time_seed_64()
state u64 = util.time_seed_64()
has_extra bool = false
extra u32
}
@ -30,7 +32,7 @@ pub fn (mut rng SplitMix64RNG) u32() u32 {
return rng.extra
}
full_value := rng.u64()
lower := u32(full_value & lower_mask)
lower := u32(full_value & util.lower_mask)
upper := u32(full_value >> 32)
rng.extra = upper
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
[inline]
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
[inline]
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)
@ -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)
[inline]
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)
[inline]
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)

View File

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

View File

@ -1,9 +1,10 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module sys
import math.bits
import rand.util
// Implementation note:
// ====================
@ -27,20 +28,6 @@ fn calculate_iterations_for(bits int) int {
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)
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.
pub struct SysRNG {
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.
@ -188,13 +175,13 @@ pub fn (r SysRNG) i64() i64 {
// r.int31() returns a pseudorandom 31-bit int which is non-negative
[inline]
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
[inline]
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)
@ -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)
[inline]
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)
[inline]
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)

View File

@ -1,7 +1,7 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module sys
// 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

View File

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

View File

@ -1,13 +1,19 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module util
import time
// Commonly used constants across RNGs
const (
lower_mask = u64(0x00000000ffffffff)
pub const (
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
@ -16,7 +22,7 @@ fn nr_next(prev u32) u32 {
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]
pub fn time_seed_array(count int) []u32 {
mut seed := u32(time.now().unix_time())
@ -28,13 +34,15 @@ pub fn time_seed_array(count int) []u32 {
return seed_data
}
// time_seed_32 returns a 32-bit seed geenrated from system time
[inline]
fn time_seed_32() u32 {
pub fn time_seed_32() u32 {
return time_seed_array(1)[0]
}
// time_seed_64 returns a 64-bit seed geenrated from system time
[inline]
fn time_seed_64() u64 {
pub fn time_seed_64() u64 {
seed_data := time_seed_array(2)
lower := u64(seed_data[0])
upper := u64(seed_data[1])

View File

@ -1,9 +1,10 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
module wyrand
import math.bits
import rand.util
import hash.wyhash
// Redefinition of some constants that we will need for pseudorandom number generation
@ -15,7 +16,7 @@ const (
// RNG based on the WyHash hashing algorithm
pub struct WyRandRNG {
mut:
state u64 = time_seed_64()
state u64 = util.time_seed_64()
has_extra bool = false
extra u32
}
@ -30,7 +31,6 @@ pub fn (mut rng WyRandRNG) seed(seed_data []u32) {
rng.has_extra = false
}
// rng.u32() updates the PRNG state and returns the next pseudorandom u32
[inline]
pub fn (mut rng WyRandRNG) u32() u32 {
@ -39,7 +39,7 @@ pub fn (mut rng WyRandRNG) u32() u32 {
return rng.extra
}
full_value := rng.u64()
lower := u32(full_value & lower_mask)
lower := u32(full_value & util.lower_mask)
upper := u32(full_value >> 32)
rng.extra = upper
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
[inline]
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
[inline]
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)
@ -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)
[inline]
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)
[inline]
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)

View File

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

View File

@ -8,5 +8,5 @@ const (
)
// random returns a random time struct in *the past*.
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() {
// 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()
t2 := tmisc.random()
t3 := tmisc.random()