2023-03-28 23:55:57 +03:00
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
2019-06-23 05:21:30 +03:00
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
2021-11-16 12:44:36 +03:00
[ has_globals ]
2019-06-22 21:20:28 +03:00
module rand
2022-02-23 13:36:14 +03:00
import math . bits
2021-08-18 11:33:37 +03:00
import rand . config
2022-02-23 13:36:14 +03:00
import rand . constants
2020-06-09 16:06:07 +03:00
import rand . wyrand
2022-03-12 10:41:12 +03:00
import time
2020-07-26 13:10:56 +03:00
2021-03-03 14:41:00 +03:00
// PRNG is a common interface for all PRNGs that can be used seamlessly with the rand
// modules's API. It defines all the methods that a PRNG (in the vlib or custom made) must
// implement in order to ensure that _all_ functions can be used with the generator.
pub interface PRNG {
2021-10-11 15:41:31 +03:00
mut :
2021-03-03 14:41:00 +03:00
seed ( seed_data [ ] u32 )
2022-04-15 18:25:45 +03:00
u8 ( ) u8
2022-02-28 14:17:54 +03:00
u16 ( ) u16
2021-03-03 14:41:00 +03:00
u32 ( ) u32
u64 ( ) u64
2022-02-28 14:17:54 +03:00
block_size ( ) int
2021-09-23 11:14:20 +03:00
free ( )
2021-03-03 14:41:00 +03:00
}
2022-02-28 14:17:54 +03:00
// bytes returns a buffer of `bytes_needed` random bytes
2022-02-23 13:36:14 +03:00
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) bytes ( bytes_needed int ) ! [ ] u8 {
2022-02-23 13:36:14 +03:00
if bytes_needed < 0 {
return error ( ' c a n n o t r e a d < 0 r a n d o m b y t e s ' )
}
2022-02-28 14:17:54 +03:00
2022-04-15 15:35:35 +03:00
mut buffer := [ ] u8 { len : bytes_needed }
2022-02-28 14:17:54 +03:00
read_internal ( mut rng , mut buffer )
return buffer
2022-02-23 13:36:14 +03:00
}
2022-03-12 10:41:12 +03:00
// read fills in `buf` with a maximum of `buf.len` random bytes
2022-04-15 15:35:35 +03:00
pub fn ( mut rng PRNG ) read ( mut buf [ ] u8 ) {
2022-03-12 10:41:12 +03:00
read_internal ( mut rng , mut buf )
}
2022-02-23 13:36:14 +03:00
// u32n returns a uniformly distributed pseudorandom 32-bit signed positive `u32` in range `[0, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) u32n ( max u32 ) ! u32 {
2022-02-23 13:36:14 +03:00
if max == 0 {
return error ( ' m a x m u s t b e p o s i t i v e i n t e g e r ' )
}
// Owing to the pigeon-hole principle, we can't simply do
// val := rng.u32() % max.
// It'll wreck the properties of the distribution unless
// max evenly divides 2^32. So we divide evenly to
// the closest power of two. Then we loop until we find
// an int in the required range
bit_len := bits . len_32 ( max )
2023-06-29 22:11:27 +03:00
if _unlikely_ ( bit_len == 32 ) {
2022-02-23 13:36:14 +03:00
for {
value := rng . u32 ( )
if value < max {
return value
}
}
} else {
2023-06-29 22:11:27 +03:00
mask := if _unlikely_ ( bit_len == 31 ) {
u32 ( 0x7FFFFFFF )
} else {
( u32 ( 1 ) << ( bit_len + 1 ) ) - 1
}
2022-02-23 13:36:14 +03:00
for {
value := rng . u32 ( ) & mask
if value < max {
return value
}
}
}
return u32 ( 0 )
}
// u64n returns a uniformly distributed pseudorandom 64-bit signed positive `u64` in range `[0, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) u64n ( max u64 ) ! u64 {
2022-02-23 13:36:14 +03:00
if max == 0 {
return error ( ' m a x m u s t b e p o s i t i v e i n t e g e r ' )
}
bit_len := bits . len_64 ( max )
2023-06-29 22:11:27 +03:00
if _unlikely_ ( bit_len == 64 ) {
2022-02-23 13:36:14 +03:00
for {
value := rng . u64 ( )
if value < max {
return value
}
}
} else {
2023-06-29 22:11:27 +03:00
mask := if _unlikely_ ( bit_len == 63 ) {
u64 ( 0x7FFFFFFFFFFFFFFF )
} else {
( u64 ( 1 ) << ( bit_len + 1 ) ) - 1
}
2022-02-23 13:36:14 +03:00
for {
value := rng . u64 ( ) & mask
if value < max {
return value
}
}
}
return u64 ( 0 )
}
// u32_in_range returns a uniformly distributed pseudorandom 32-bit unsigned `u32` in range `[min, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) u32_in_range ( min u32 , max u32 ) ! u32 {
2022-02-23 13:36:14 +03:00
if max <= min {
return error ( ' m a x m u s t b e g r e a t e r t h a n m i n ' )
}
2022-10-20 22:14:33 +03:00
return min + rng . u32n ( max - min ) !
2022-02-23 13:36:14 +03:00
}
// u64_in_range returns a uniformly distributed pseudorandom 64-bit unsigned `u64` in range `[min, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) u64_in_range ( min u64 , max u64 ) ! u64 {
2022-02-23 13:36:14 +03:00
if max <= min {
return error ( ' m a x m u s t b e g r e a t e r t h a n m i n ' )
}
2022-10-20 22:14:33 +03:00
return min + rng . u64n ( max - min ) !
2022-02-23 13:36:14 +03:00
}
2022-02-28 14:17:54 +03:00
// i8 returns a (possibly negative) pseudorandom 8-bit `i8`.
[ inline ]
pub fn ( mut rng PRNG ) i8 ( ) i8 {
2022-04-15 14:58:56 +03:00
return i8 ( rng . u8 ( ) )
2022-02-28 14:17:54 +03:00
}
// i16 returns a (possibly negative) pseudorandom 16-bit `i16`.
[ inline ]
pub fn ( mut rng PRNG ) i16 ( ) i16 {
return i16 ( rng . u16 ( ) )
}
2022-02-23 13:36:14 +03:00
// int returns a (possibly negative) pseudorandom 32-bit `int`.
[ inline ]
pub fn ( mut rng PRNG ) int ( ) int {
return int ( rng . u32 ( ) )
}
// i64 returns a (possibly negative) pseudorandom 64-bit `i64`.
[ inline ]
pub fn ( mut rng PRNG ) i64 ( ) i64 {
return i64 ( rng . u64 ( ) )
}
// int31 returns a positive pseudorandom 31-bit `int`.
[ inline ]
pub fn ( mut rng PRNG ) int31 ( ) int {
return int ( rng . u32 ( ) & constants . u31_mask ) // Set the 32nd bit to 0.
}
// int63 returns a positive pseudorandom 63-bit `i64`.
[ inline ]
pub fn ( mut rng PRNG ) int63 ( ) i64 {
return i64 ( rng . u64 ( ) & constants . u63_mask ) // Set the 64th bit to 0.
}
// intn returns a pseudorandom `int` in range `[0, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) intn ( max int ) ! int {
2022-02-23 13:36:14 +03:00
if max <= 0 {
return error ( ' m a x h a s t o b e p o s i t i v e . ' )
}
2022-10-20 22:14:33 +03:00
return int ( rng . u32n ( u32 ( max ) ) ! )
2022-02-23 13:36:14 +03:00
}
// i64n returns a pseudorandom int that lies in `[0, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) i64n ( max i64 ) ! i64 {
2022-02-23 13:36:14 +03:00
if max <= 0 {
return error ( ' m a x h a s t o b e p o s i t i v e . ' )
}
2022-10-20 22:14:33 +03:00
return i64 ( rng . u64n ( u64 ( max ) ) ! )
2022-02-23 13:36:14 +03:00
}
// int_in_range returns a pseudorandom `int` in range `[min, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) int_in_range ( min int , max int ) ! int {
2022-02-23 13:36:14 +03:00
if max <= min {
return error ( ' m a x m u s t b e g r e a t e r t h a n m i n ' )
}
// This supports negative ranges like [-10, -5) because the difference is positive
2022-10-20 22:14:33 +03:00
return min + rng . intn ( max - min ) !
2022-02-23 13:36:14 +03:00
}
// i64_in_range returns a pseudorandom `i64` in range `[min, max)`.
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) i64_in_range ( min i64 , max i64 ) ! i64 {
2022-02-23 13:36:14 +03:00
if max <= min {
return error ( ' m a x m u s t b e g r e a t e r t h a n m i n ' )
}
2022-10-20 22:14:33 +03:00
return min + rng . i64n ( max - min ) !
2022-02-23 13:36:14 +03:00
}
2023-01-19 16:21:47 +03:00
// f32 returns a pseudorandom `f32` value in range `[0, 1)`
// using rng.u32() multiplied by an f64 constant.
2022-02-23 13:36:14 +03:00
[ inline ]
pub fn ( mut rng PRNG ) f32 ( ) f32 {
2023-01-19 16:21:47 +03:00
return f32 ( ( rng . u32 ( ) >> 9 ) * constants . reciprocal_2_23rd )
2022-02-23 13:36:14 +03:00
}
2023-01-19 16:21:47 +03:00
// f32cp returns a pseudorandom `f32` value in range `[0, 1)`
// with full precision (mantissa random between 0 and 1
// and the exponent varies as well.)
// See https://allendowney.com/research/rand/ for background on the method.
[ inline ]
pub fn ( mut rng PRNG ) f32cp ( ) f32 {
mut x := rng . u32 ( )
mut exp := u32 ( 126 )
mut mask := u32 ( 1 ) << 31
// check if prng returns 0; rare but keep looking for precision
if _unlikely_ ( x == 0 ) {
x = rng . u32 ( )
exp -= 31
}
// count leading one bits and scale exponent accordingly
for {
if x & mask != 0 {
mask >>= 1
exp -= 1
} else {
break
}
}
// if we used any high-order mantissa bits; replace x
if exp < ( 126 - 8 ) {
x = rng . u32 ( )
}
// Assumes little-endian IEEE floating point.
x = ( exp << 23 ) | ( x >> 8 ) & constants . ieee754_mantissa_f32_mask
return bits . f32_from_bits ( x )
}
// f64 returns a pseudorandom `f64` value in range `[0, 1)`
// using rng.u64() multiplied by a constant.
2022-02-23 13:36:14 +03:00
[ inline ]
pub fn ( mut rng PRNG ) f64 ( ) f64 {
2023-01-19 16:21:47 +03:00
return f64 ( ( rng . u64 ( ) >> 12 ) * constants . reciprocal_2_52nd )
}
// f64cp returns a pseudorandom `f64` value in range `[0, 1)`
// with full precision (mantissa random between 0 and 1
// and the exponent varies as well.)
// See https://allendowney.com/research/rand/ for background on the method.
[ inline ]
pub fn ( mut rng PRNG ) f64cp ( ) f64 {
mut x := rng . u64 ( )
mut exp := u64 ( 1022 )
mut mask := u64 ( 1 ) << 63
mut bitcount := u32 ( 0 )
// check if prng returns 0; unlikely.
if _unlikely_ ( x == 0 ) {
x = rng . u64 ( )
exp -= 31
}
// count leading one bits and scale exponent accordingly
for {
if x & mask != 0 {
mask >>= 1
bitcount += 1
} else {
break
}
}
exp -= bitcount
if bitcount > 11 {
x = rng . u64 ( )
}
x = ( exp << 52 ) | ( x & constants . ieee754_mantissa_f64_mask )
return bits . f64_from_bits ( x )
2022-02-23 13:36:14 +03:00
}
2022-02-28 14:17:54 +03:00
// f32n returns a pseudorandom `f32` value in range `[0, max]`.
2022-02-23 13:36:14 +03:00
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) f32n ( max f32 ) ! f32 {
2022-02-28 14:17:54 +03:00
if max < 0 {
return error ( ' m a x h a s t o b e n o n - n e g a t i v e . ' )
2022-02-23 13:36:14 +03:00
}
return rng . f32 ( ) * max
}
2022-02-28 14:17:54 +03:00
// f64n returns a pseudorandom `f64` value in range `[0, max]`.
2022-02-23 13:36:14 +03:00
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) f64n ( max f64 ) ! f64 {
2022-02-28 14:17:54 +03:00
if max < 0 {
return error ( ' m a x h a s t o b e n o n - n e g a t i v e . ' )
2022-02-23 13:36:14 +03:00
}
return rng . f64 ( ) * max
}
2022-02-28 14:17:54 +03:00
// f32_in_range returns a pseudorandom `f32` in range `[min, max]`.
2022-02-23 13:36:14 +03:00
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) f32_in_range ( min f32 , max f32 ) ! f32 {
2022-02-28 14:17:54 +03:00
if max < min {
return error ( ' m a x m u s t b e g r e a t e r t h a n o r e q u a l t o m i n ' )
2022-02-23 13:36:14 +03:00
}
2022-10-20 22:14:33 +03:00
return min + rng . f32n ( max - min ) !
2022-02-23 13:36:14 +03:00
}
2022-02-28 14:17:54 +03:00
// i64_in_range returns a pseudorandom `i64` in range `[min, max]`.
2022-02-23 13:36:14 +03:00
[ inline ]
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) f64_in_range ( min f64 , max f64 ) ! f64 {
2022-02-28 14:17:54 +03:00
if max < min {
return error ( ' m a x m u s t b e g r e a t e r t h a n o r e q u a l t o m i n ' )
2022-02-23 13:36:14 +03:00
}
2022-10-20 22:14:33 +03:00
return min + rng . f64n ( max - min ) !
2022-02-23 13:36:14 +03:00
}
2022-03-12 10:41:12 +03:00
// ulid generates an Unique Lexicographically sortable IDentifier.
// See https://github.com/ulid/spec .
// Note: ULIDs can leak timing information, if you make them public, because
// you can infer the rate at which some resource is being created, like
// users or business transactions.
// (https://news.ycombinator.com/item?id=14526173)
pub fn ( mut rng PRNG ) ulid ( ) string {
return internal_ulid_at_millisecond ( mut rng , u64 ( time . utc ( ) . unix_time_milli ( ) ) )
}
// ulid_at_millisecond does the same as `ulid` but takes a custom Unix millisecond timestamp via `unix_time_milli`.
pub fn ( mut rng PRNG ) ulid_at_millisecond ( unix_time_milli u64 ) string {
return internal_ulid_at_millisecond ( mut rng , unix_time_milli )
}
// string_from_set returns a string of length `len` containing random characters sampled from the given `charset`
pub fn ( mut rng PRNG ) string_from_set ( charset string , len int ) string {
return internal_string_from_set ( mut rng , charset , len )
}
// string returns a string of length `len` containing random characters in range `[a-zA-Z]`.
pub fn ( mut rng PRNG ) string ( len int ) string {
return internal_string_from_set ( mut rng , rand . english_letters , len )
}
// hex returns a hexadecimal number of length `len` containing random characters in range `[a-f0-9]`.
pub fn ( mut rng PRNG ) hex ( len int ) string {
return internal_string_from_set ( mut rng , rand . hex_chars , len )
}
// ascii returns a random string of the printable ASCII characters with length `len`.
pub fn ( mut rng PRNG ) ascii ( len int ) string {
return internal_string_from_set ( mut rng , rand . ascii_chars , len )
}
2022-05-22 13:21:52 +03:00
// bernoulli returns true with a probability p. Note that 0 <= p <= 1.
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) bernoulli ( p f64 ) ! bool {
2022-05-22 13:21:52 +03:00
if p < 0 || p > 1 {
2022-11-15 16:53:13 +03:00
return error ( ' $ { p } i s n o t a v a l i d p r o b a b i l i t y v a l u e . ' )
2022-03-27 17:38:59 +03:00
}
2022-05-22 13:21:52 +03:00
return rng . f64 ( ) <= p
}
2023-04-06 17:52:09 +03:00
// normal returns a normally distributed pseudorandom f64 with mean `mu` and standard
// deviation `sigma`. By default, `mu` is 0.0 and `sigma` is 1.0.
2022-05-22 13:21:52 +03:00
// NOTE: Use normal_pair() instead if you're generating a lot of normal variates.
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) normal ( conf config . NormalConfigStruct ) ! f64 {
x , _ := rng . normal_pair ( conf ) !
2022-05-22 13:21:52 +03:00
return x
}
2023-04-06 17:52:09 +03:00
// normal_pair returns a pair of normally distributed pseudorandom f64 with mean `mu` and standard
// deviation `sigma`. By default, `mu` is 0.0 and `sigma` is 1.0.
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) normal_pair ( conf config . NormalConfigStruct ) ! ( f64 , f64 ) {
2022-05-22 13:21:52 +03:00
if conf . sigma <= 0 {
return error ( ' S t a n d a r d d e v i a t i o n m u s t b e p o s i t i v e ' )
}
// This is an implementation of the Marsaglia polar method
// See: https://doi.org/10.1137%2F1006063
// Also: https://en.wikipedia.org/wiki/Marsaglia_polar_method
for {
u := rng . f64_in_range ( - 1 , 1 ) or { 0.0 }
v := rng . f64_in_range ( - 1 , 1 ) or { 0.0 }
s := u * u + v * v
if s >= 1 || s == 0 {
continue
}
t := msqrt ( - 2 * mlog ( s ) / s )
x := conf . mu + conf . sigma * t * u
y := conf . mu + conf . sigma * t * v
return x , y
}
return error ( ' I m p l e m e n t a t i o n e r r o r . P l e a s e f i l e a n i s s u e . ' )
}
// binomial returns the number of successful trials out of n when the
// probability of success for each trial is p.
2022-10-20 22:14:33 +03:00
pub fn ( mut rng PRNG ) binomial ( n int , p f64 ) ! int {
2022-05-22 13:21:52 +03:00
if p < 0 || p > 1 {
2022-11-15 16:53:13 +03:00
return error ( ' $ { p } i s n o t a v a l i d p r o b a b i l i t y v a l u e . ' )
2022-05-22 13:21:52 +03:00
}
mut count := 0
for _ in 0 .. n {
if rng . bernoulli ( p ) ! {
count ++
}
}
return count
}
// exponential returns an exponentially distributed random number with the rate paremeter
// lambda. It is expected that lambda is positive.
pub fn ( mut rng PRNG ) exponential ( lambda f64 ) f64 {
if lambda <= 0 {
panic ( ' T h e r a t e ( l a m b d a ) m u s t b e p o s i t i v e . ' )
2022-03-27 17:38:59 +03:00
}
2022-05-22 13:21:52 +03:00
// Use the inverse transform sampling method
return - mlog ( rng . f64 ( ) ) / lambda
2022-03-27 17:38:59 +03:00
}
// shuffle randomly permutates the elements in `a`. The range for shuffling is
// optional and the entire array is shuffled by default. Leave the end as 0 to
// shuffle all elements until the end.
[ direct_array_access ]
2023-02-08 21:37:04 +03:00
pub fn ( mut rng PRNG ) shuffle [ T ] ( mut a [ ] T , config_ config . ShuffleConfigStruct ) ! {
config_ . validate_for ( a ) !
new_end := if config_ . end == 0 { a . len } else { config_ . end }
2022-08-02 20:11:49 +03:00
// We implement the Fisher-Yates shuffle:
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
2023-02-08 21:37:04 +03:00
for i in config_ . start .. new_end - 2 {
2022-08-02 20:11:49 +03:00
x := rng . int_in_range ( i , new_end ) or { i }
2022-03-27 17:38:59 +03:00
// swap
a_i := a [ i ]
a [ i ] = a [ x ]
a [ x ] = a_i
}
}
// shuffle_clone returns a random permutation of the elements in `a`.
// The permutation is done on a fresh clone of `a`, so `a` remains unchanged.
2023-02-08 21:37:04 +03:00
pub fn ( mut rng PRNG ) shuffle_clone [ T ] ( a [ ] T , config_ config . ShuffleConfigStruct ) ! [ ] T {
2022-03-27 17:38:59 +03:00
mut res := a . clone ( )
2023-02-08 21:37:04 +03:00
rng . shuffle [ T ] ( mut res , config_ ) !
2022-03-27 17:38:59 +03:00
return res
}
// choose samples k elements from the array without replacement.
// This means the indices cannot repeat and it restricts the sample size to be less than or equal to the size of the given array.
// Note that if the array has repeating elements, then the sample may have repeats as well.
2022-11-26 19:23:26 +03:00
pub fn ( mut rng PRNG ) choose [ T ] ( array [ ] T , k int ) ! [ ] T {
2022-03-27 17:38:59 +03:00
n := array . len
if k > n {
2022-11-15 16:53:13 +03:00
return error ( ' C a n n o t c h o o s e $ { k } e l e m e n t s w i t h o u t r e p l a c e m e n t f r o m a $ { n } - e l e m e n t a r r a y . ' )
2022-03-27 17:38:59 +03:00
}
mut results := [ ] T { len : k }
2023-03-08 22:51:45 +03:00
mut indices := [ ] int { len : n , init : index }
2022-11-26 19:23:26 +03:00
rng . shuffle [ int ] ( mut indices ) !
2022-03-27 17:38:59 +03:00
for i in 0 .. k {
results [ i ] = array [ indices [ i ] ]
}
return results
}
2022-10-14 06:54:02 +03:00
// element returns a random element from the given array.
// Note that all the positions in the array have an equal chance of being selected. This means that if the array has repeating elements, then the probability of selecting a particular element is not uniform.
2022-11-26 19:23:26 +03:00
pub fn ( mut rng PRNG ) element [ T ] ( array [ ] T ) ! T {
2022-10-14 06:54:02 +03:00
if array . len == 0 {
return error ( ' C a n n o t c h o o s e a n e l e m e n t f r o m a n e m p t y a r r a y . ' )
}
return array [ rng . intn ( array . len ) ! ]
}
2022-03-27 17:38:59 +03:00
// sample samples k elements from the array with replacement.
// This means the elements can repeat and the size of the sample may exceed the size of the array.
2022-11-26 19:23:26 +03:00
pub fn ( mut rng PRNG ) sample [ T ] ( array [ ] T , k int ) [ ] T {
2022-03-27 17:38:59 +03:00
mut results := [ ] T { len : k }
for i in 0 .. k {
results [ i ] = array [ rng . intn ( array . len ) or { 0 } ]
}
return results
}
2021-11-16 12:44:36 +03:00
__global default_rng & PRNG
2021-03-03 09:36:56 +03:00
2020-06-09 16:06:07 +03:00
// 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.
2021-09-23 11:14:20 +03:00
[ manualfree ]
2023-02-08 21:37:04 +03:00
pub fn new_default ( config_ config . PRNGConfigStruct ) & PRNG {
2020-07-24 02:55:55 +03:00
mut rng := & wyrand . WyRandRNG { }
2023-02-08 21:37:04 +03:00
rng . seed ( config_ . seed_ )
unsafe { config_ . seed_ . free ( ) }
2021-09-23 11:14:20 +03:00
return & PRNG ( rng )
2019-09-16 22:21:21 +03:00
}
2020-05-27 16:41:37 +03:00
2021-03-03 14:41:00 +03:00
// get_current_rng returns the PRNG instance currently in use. If it is not changed, it will be an instance of wyrand.WyRandRNG.
pub fn get_current_rng ( ) & PRNG {
return default_rng
}
// set_rng changes the default RNG from wyrand.WyRandRNG (or whatever the last RNG was) to the one
2021-05-08 13:32:29 +03:00
// provided by the user. Note that this new RNG must be seeded manually with a constant seed or the
2021-03-03 14:41:00 +03:00
// `seed.time_seed_array()` method. Also, it is recommended to store the old RNG in a variable and
// should be restored if work with the custom RNG is complete. It is not necessary to restore if the
// program terminates soon afterwards.
pub fn set_rng ( rng & PRNG ) {
2021-05-07 15:58:48 +03:00
default_rng = unsafe { rng }
2021-03-03 14:41:00 +03:00
}
2021-03-12 22:24:43 +03:00
// seed sets the given array of `u32` values as the seed for the `default_rng`. The default_rng is
// an instance of WyRandRNG which takes 2 u32 values. When using a custom RNG, make sure to use
// the correct number of u32s.
2020-06-09 16:06:07 +03:00
pub fn seed ( seed [ ] u32 ) {
2021-03-03 09:36:56 +03:00
default_rng . seed ( seed )
2020-06-01 22:13:56 +03:00
}
2023-05-22 13:15:07 +03:00
// u8 returns a uniformly distributed pseudorandom 8-bit unsigned positive `u8`.
pub fn u8 ( ) u8 {
return default_rng . u8 ( )
}
// u16 returns a uniformly distributed pseudorandom 16-bit unsigned positive `u16`.
pub fn u16 ( ) u16 {
return default_rng . u16 ( )
}
2020-12-27 21:06:17 +03:00
// u32 returns a uniformly distributed `u32` in range `[0, 2³²)`.
2020-06-09 16:06:07 +03:00
pub fn u32 ( ) u32 {
2021-03-03 09:36:56 +03:00
return default_rng . u32 ( )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// u64 returns a uniformly distributed `u64` in range `[0, 2⁶⁴)`.
2020-06-09 16:06:07 +03:00
pub fn u64 ( ) u64 {
2021-03-03 09:36:56 +03:00
return default_rng . u64 ( )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// u32n returns a uniformly distributed pseudorandom 32-bit signed positive `u32` in range `[0, max)`.
2022-10-20 22:14:33 +03:00
pub fn u32n ( max u32 ) ! u32 {
2021-03-03 09:36:56 +03:00
return default_rng . u32n ( max )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// u64n returns a uniformly distributed pseudorandom 64-bit signed positive `u64` in range `[0, max)`.
2022-10-20 22:14:33 +03:00
pub fn u64n ( max u64 ) ! u64 {
2021-03-03 09:36:56 +03:00
return default_rng . u64n ( max )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// u32_in_range returns a uniformly distributed pseudorandom 32-bit unsigned `u32` in range `[min, max)`.
2022-10-20 22:14:33 +03:00
pub fn u32_in_range ( min u32 , max u32 ) ! u32 {
2021-03-03 09:36:56 +03:00
return default_rng . u32_in_range ( min , max )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// u64_in_range returns a uniformly distributed pseudorandom 64-bit unsigned `u64` in range `[min, max)`.
2022-10-20 22:14:33 +03:00
pub fn u64_in_range ( min u64 , max u64 ) ! u64 {
2021-03-03 09:36:56 +03:00
return default_rng . u64_in_range ( min , max )
2020-06-09 16:06:07 +03:00
}
2022-02-28 14:17:54 +03:00
// i16 returns a uniformly distributed pseudorandom 16-bit signed (possibly negative) `i16`.
pub fn i16 ( ) i16 {
return default_rng . i16 ( )
}
2020-12-27 21:06:17 +03:00
// int returns a uniformly distributed pseudorandom 32-bit signed (possibly negative) `int`.
2020-06-09 16:06:07 +03:00
pub fn int ( ) int {
2021-03-03 09:36:56 +03:00
return default_rng . int ( )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// intn returns a uniformly distributed pseudorandom 32-bit signed positive `int` in range `[0, max)`.
2022-10-20 22:14:33 +03:00
pub fn intn ( max int ) ! int {
2021-03-03 09:36:56 +03:00
return default_rng . intn ( max )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// int_in_range returns a uniformly distributed pseudorandom 32-bit signed int in range `[min, max)`.
// Both `min` and `max` can be negative, but we must have `min < max`.
2022-10-20 22:14:33 +03:00
pub fn int_in_range ( min int , max int ) ! int {
2021-03-03 09:36:56 +03:00
return default_rng . int_in_range ( min , max )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// int31 returns a uniformly distributed pseudorandom 31-bit signed positive `int`.
2020-06-09 16:06:07 +03:00
pub fn int31 ( ) int {
2021-03-03 09:36:56 +03:00
return default_rng . int31 ( )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// i64 returns a uniformly distributed pseudorandom 64-bit signed (possibly negative) `i64`.
2020-06-09 16:06:07 +03:00
pub fn i64 ( ) i64 {
2021-03-03 09:36:56 +03:00
return default_rng . i64 ( )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// i64n returns a uniformly distributed pseudorandom 64-bit signed positive `i64` in range `[0, max)`.
2022-10-20 22:14:33 +03:00
pub fn i64n ( max i64 ) ! i64 {
2021-03-03 09:36:56 +03:00
return default_rng . i64n ( max )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// i64_in_range returns a uniformly distributed pseudorandom 64-bit signed `i64` in range `[min, max)`.
2022-10-20 22:14:33 +03:00
pub fn i64_in_range ( min i64 , max i64 ) ! i64 {
2021-03-03 09:36:56 +03:00
return default_rng . i64_in_range ( min , max )
2020-06-09 16:06:07 +03:00
}
2020-12-27 21:06:17 +03:00
// int63 returns a uniformly distributed pseudorandom 63-bit signed positive `i64`.
2020-06-09 16:06:07 +03:00
pub fn int63 ( ) i64 {
2021-03-03 09:36:56 +03:00
return default_rng . int63 ( )
2020-06-01 22:13:56 +03:00
}
2020-12-27 21:06:17 +03:00
// f32 returns a uniformly distributed 32-bit floating point in range `[0, 1)`.
2020-06-09 16:06:07 +03:00
pub fn f32 ( ) f32 {
2021-03-03 09:36:56 +03:00
return default_rng . f32 ( )
2020-05-27 16:41:37 +03:00
}
2023-01-19 16:21:47 +03:00
// f32cp returns a uniformly distributed 32-bit floating point in range `[0, 1)`
// with full precision mantissa.
pub fn f32cp ( ) f32 {
return default_rng . f32cp ( )
}
2020-12-27 21:06:17 +03:00
// f64 returns a uniformly distributed 64-bit floating point in range `[0, 1)`.
2020-06-09 16:06:07 +03:00
pub fn f64 ( ) f64 {
2021-03-03 09:36:56 +03:00
return default_rng . f64 ( )
2020-05-27 16:41:37 +03:00
}
2023-01-19 16:21:47 +03:00
// f64 returns a uniformly distributed 64-bit floating point in range `[0, 1)`
// with full precision mantissa.
pub fn f64cp ( ) f64 {
return default_rng . f64cp ( )
}
2020-12-27 21:06:17 +03:00
// f32n returns a uniformly distributed 32-bit floating point in range `[0, max)`.
2022-10-20 22:14:33 +03:00
pub fn f32n ( max f32 ) ! f32 {
2021-03-03 09:36:56 +03:00
return default_rng . f32n ( max )
2020-05-27 16:41:37 +03:00
}
2020-12-27 21:06:17 +03:00
// f64n returns a uniformly distributed 64-bit floating point in range `[0, max)`.
2022-10-20 22:14:33 +03:00
pub fn f64n ( max f64 ) ! f64 {
2021-03-03 09:36:56 +03:00
return default_rng . f64n ( max )
2020-05-28 02:16:17 +03:00
}
2020-12-27 21:06:17 +03:00
// f32_in_range returns a uniformly distributed 32-bit floating point in range `[min, max)`.
2022-10-20 22:14:33 +03:00
pub fn f32_in_range ( min f32 , max f32 ) ! f32 {
2021-03-03 09:36:56 +03:00
return default_rng . f32_in_range ( min , max )
2020-05-27 20:13:57 +03:00
}
2020-05-28 02:16:17 +03:00
2020-12-27 21:06:17 +03:00
// f64_in_range returns a uniformly distributed 64-bit floating point in range `[min, max)`.
2022-10-20 22:14:33 +03:00
pub fn f64_in_range ( min f64 , max f64 ) ! f64 {
2021-03-03 09:36:56 +03:00
return default_rng . f64_in_range ( min , max )
2020-06-01 22:13:56 +03:00
}
2020-07-15 22:36:06 +03:00
2022-02-06 11:49:43 +03:00
// bytes returns a buffer of `bytes_needed` random bytes
2022-10-20 22:14:33 +03:00
pub fn bytes ( bytes_needed int ) ! [ ] u8 {
2022-02-23 13:36:14 +03:00
return default_rng . bytes ( bytes_needed )
2022-02-06 11:49:43 +03:00
}
2022-02-28 14:17:54 +03:00
// read fills in `buf` a maximum of `buf.len` random bytes
2022-04-15 15:35:35 +03:00
pub fn read ( mut buf [ ] u8 ) {
2022-02-28 14:17:54 +03:00
read_internal ( mut default_rng , mut buf )
}
2020-07-15 22:36:06 +03:00
const (
2021-02-19 12:16:02 +03:00
english_letters = ' a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z '
hex_chars = ' a b c d e f 0 1 2 3 4 5 6 7 8 9 '
ascii_chars = ' ! " # $ % & \' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \\ ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ '
2020-07-15 22:36:06 +03:00
)
2022-03-12 10:41:12 +03:00
// ulid generates an Unique Lexicographically sortable IDentifier.
// See https://github.com/ulid/spec .
// Note: ULIDs can leak timing information, if you make them public, because
// you can infer the rate at which some resource is being created, like
// users or business transactions.
// (https://news.ycombinator.com/item?id=14526173)
pub fn ulid ( ) string {
2022-03-27 17:38:59 +03:00
return default_rng . ulid ( )
2022-03-12 10:41:12 +03:00
}
// ulid_at_millisecond does the same as `ulid` but takes a custom Unix millisecond timestamp via `unix_time_milli`.
pub fn ulid_at_millisecond ( unix_time_milli u64 ) string {
2022-03-27 17:38:59 +03:00
return default_rng . ulid_at_millisecond ( unix_time_milli )
2022-03-12 10:41:12 +03:00
}
// string_from_set returns a string of length `len` containing random characters sampled from the given `charset`
pub fn string_from_set ( charset string , len int ) string {
2022-03-27 17:38:59 +03:00
return default_rng . string_from_set ( charset , len )
2022-03-12 10:41:12 +03:00
}
// string returns a string of length `len` containing random characters in range `[a-zA-Z]`.
pub fn string ( len int ) string {
return string_from_set ( rand . english_letters , len )
}
// hex returns a hexadecimal number of length `len` containing random characters in range `[a-f0-9]`.
pub fn hex ( len int ) string {
return string_from_set ( rand . hex_chars , len )
}
// ascii returns a random string of the printable ASCII characters with length `len`.
pub fn ascii ( len int ) string {
return string_from_set ( rand . ascii_chars , len )
}
2022-03-23 16:31:26 +03:00
2022-03-27 17:38:59 +03:00
// shuffle randomly permutates the elements in `a`. The range for shuffling is
// optional and the entire array is shuffled by default. Leave the end as 0 to
// shuffle all elements until the end.
2023-02-08 21:37:04 +03:00
pub fn shuffle [ T ] ( mut a [ ] T , config_ config . ShuffleConfigStruct ) ! {
default_rng . shuffle [ T ] ( mut a , config_ ) !
2022-03-23 16:31:26 +03:00
}
// shuffle_clone returns a random permutation of the elements in `a`.
// The permutation is done on a fresh clone of `a`, so `a` remains unchanged.
2023-02-08 21:37:04 +03:00
pub fn shuffle_clone [ T ] ( a [ ] T , config_ config . ShuffleConfigStruct ) ! [ ] T {
return default_rng . shuffle_clone [ T ] ( a , config_ )
2022-03-27 17:38:59 +03:00
}
// choose samples k elements from the array without replacement.
// This means the indices cannot repeat and it restricts the sample size to be less than or equal to the size of the given array.
// Note that if the array has repeating elements, then the sample may have repeats as well.
2022-11-26 19:23:26 +03:00
pub fn choose [ T ] ( array [ ] T , k int ) ! [ ] T {
return default_rng . choose [ T ] ( array , k )
2022-03-27 17:38:59 +03:00
}
2022-10-14 06:54:02 +03:00
// element returns a random element from the given array.
// Note that all the positions in the array have an equal chance of being selected. This means that if the array has repeating elements, then the probability of selecting a particular element is not uniform.
2022-11-26 19:23:26 +03:00
pub fn element [ T ] ( array [ ] T ) ! T {
return default_rng . element [ T ] ( array )
2022-10-14 06:54:02 +03:00
}
2022-03-27 17:38:59 +03:00
// sample samples k elements from the array with replacement.
// This means the elements can repeat and the size of the sample may exceed the size of the array.
2022-11-26 19:23:26 +03:00
pub fn sample [ T ] ( array [ ] T , k int ) [ ] T {
return default_rng . sample [ T ] ( array , k )
2022-03-23 16:31:26 +03:00
}
2022-05-22 13:21:52 +03:00
// bernoulli returns true with a probability p. Note that 0 <= p <= 1.
2022-10-20 22:14:33 +03:00
pub fn bernoulli ( p f64 ) ! bool {
2022-05-22 13:21:52 +03:00
return default_rng . bernoulli ( p )
}
2023-04-06 17:52:09 +03:00
// normal returns a normally distributed pseudorandom f64 with mean `mu` and standard
// deviation `sigma`. By default, `mu` is 0.0 and `sigma` is 1.0.
2022-05-22 13:21:52 +03:00
// NOTE: Use normal_pair() instead if you're generating a lot of normal variates.
2023-02-08 21:37:04 +03:00
pub fn normal ( config_ config . NormalConfigStruct ) ! f64 {
return default_rng . normal ( config_ )
2022-05-22 13:21:52 +03:00
}
2023-04-06 17:52:09 +03:00
// normal_pair returns a pair of normally distributed pseudorandom f64 with mean `mu` and standard
// deviation `sigma`. By default, `mu` is 0.0 and `sigma` is 1.0.
2023-02-08 21:37:04 +03:00
pub fn normal_pair ( config_ config . NormalConfigStruct ) ! ( f64 , f64 ) {
return default_rng . normal_pair ( config_ )
2022-05-22 13:21:52 +03:00
}
// binomial returns the number of successful trials out of n when the
// probability of success for each trial is p.
2022-10-20 22:14:33 +03:00
pub fn binomial ( n int , p f64 ) ! int {
2022-05-22 13:21:52 +03:00
return default_rng . binomial ( n , p )
}
// exponential returns an exponentially distributed random number with the rate paremeter
// lambda. It is expected that lambda is positive.
pub fn exponential ( lambda f64 ) f64 {
return default_rng . exponential ( lambda )
}