mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-31 10:22:08 +00:00
1213 lines
27 KiB
Odin
1213 lines
27 KiB
Odin
// Random number generators.
|
|
package rand
|
|
|
|
import "base:intrinsics"
|
|
import "base:runtime"
|
|
import "core:math"
|
|
import "core:mem"
|
|
|
|
Generator :: runtime.Random_Generator
|
|
|
|
Generator_Query_Info :: runtime.Random_Generator_Query_Info
|
|
|
|
Default_Random_State :: runtime.Default_Random_State
|
|
|
|
/*
|
|
Returns an instance of the runtime pseudorandom generator. If no
|
|
initial state is provided, the PRNG will be lazily initialized with
|
|
entropy from the system entropy source on first-use.
|
|
|
|
The cryptographic security of the returned random number generator
|
|
is directly dependent on the quality of the initialization entropy.
|
|
Calling `reset`/`create` SHOULD be done with no seed/state, or
|
|
32-bytes of high-quality entropy.
|
|
|
|
WARNING:
|
|
- The lazy initialization will panic if there is no system entropy
|
|
source available.
|
|
- While the generator is cryptographically secure, developers SHOULD
|
|
prefer `crypto.random_generator()` for cryptographic use cases such
|
|
as key generation.
|
|
|
|
Inputs:
|
|
- state: Optional initial PRNG state.
|
|
|
|
Returns:
|
|
- A `Generator` instance.
|
|
*/
|
|
default_random_generator :: runtime.default_random_generator
|
|
|
|
@(require_results)
|
|
create_u64 :: proc(seed: u64) -> (state: Default_Random_State) {
|
|
seed := seed
|
|
runtime.default_random_generator_proc(&state, .Reset, ([^]byte)(&seed)[:size_of(seed)])
|
|
return
|
|
}
|
|
|
|
@(require_results)
|
|
create_bytes :: proc(seed: []byte) -> (state: Default_Random_State) {
|
|
runtime.default_random_generator_proc(&state, .Reset, seed)
|
|
return
|
|
}
|
|
|
|
create :: proc {
|
|
create_u64,
|
|
create_bytes,
|
|
}
|
|
|
|
/*
|
|
Reset the seed used by the context.random_generator.
|
|
|
|
Inputs:
|
|
- seed: The seed value
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
reset_example :: proc() {
|
|
rand.reset(1)
|
|
fmt.println(rand.uint64())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
10
|
|
*/
|
|
reset :: proc {
|
|
reset_u64,
|
|
reset_bytes,
|
|
}
|
|
|
|
reset_u64 :: proc(seed: u64, gen := context.random_generator) {
|
|
runtime.random_generator_reset_u64(gen, seed)
|
|
}
|
|
|
|
reset_bytes :: proc(bytes: []byte, gen := context.random_generator) {
|
|
runtime.random_generator_reset_bytes(gen, bytes)
|
|
}
|
|
|
|
query_info :: proc(gen := context.random_generator) -> Generator_Query_Info {
|
|
return runtime.random_generator_query_info(gen)
|
|
}
|
|
|
|
|
|
/*
|
|
Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Returns:
|
|
- val: A random unsigned 32 bit value
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint32_example :: proc() {
|
|
fmt.println(rand.uint32())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
10
|
|
389
|
|
|
|
*/
|
|
@(require_results)
|
|
uint32 :: proc(gen := context.random_generator) -> (val: u32) {return u32(uint64(gen))}
|
|
|
|
/*
|
|
Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Returns:
|
|
- val: A random unsigned 64 bit value
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint64_example :: proc() {
|
|
fmt.println(rand.uint64())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
10
|
|
389
|
|
|
|
*/
|
|
@(require_results)
|
|
uint64 :: proc(gen := context.random_generator) -> (val: u64) {
|
|
ok := runtime.random_generator_read_ptr(gen, &val, size_of(val))
|
|
assert(ok, "uninitialized gen/context.random_generator")
|
|
return
|
|
}
|
|
|
|
/*
|
|
Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Returns:
|
|
- val: A random unsigned 128 bit value
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint128_example :: proc() {
|
|
fmt.println(rand.uint128())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
10
|
|
389
|
|
|
|
*/
|
|
@(require_results)
|
|
uint128 :: proc(gen := context.random_generator) -> (val: u128) {
|
|
a := u128(uint64(gen))
|
|
b := u128(uint64(gen))
|
|
return (a<<64) | b
|
|
}
|
|
|
|
/*
|
|
Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
|
|
|
Returns:
|
|
- val: A random 31 bit value
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int31_example :: proc() {
|
|
fmt.println(rand.int31())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
10
|
|
389
|
|
|
|
*/
|
|
@(require_results) int31 :: proc(gen := context.random_generator) -> (val: i32) { return i32(uint32(gen) << 1 >> 1) }
|
|
|
|
/*
|
|
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
|
|
|
Returns:
|
|
- val: A random 63 bit value
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int63_example :: proc() {
|
|
fmt.println(rand.int63())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
10
|
|
389
|
|
|
|
*/
|
|
@(require_results) int63 :: proc(gen := context.random_generator) -> (val: i64) { return i64(uint64(gen) << 1 >> 1) }
|
|
|
|
/*
|
|
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
|
|
|
Returns:
|
|
- val: A random 127 bit value
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int127_example :: proc() {
|
|
fmt.println(rand.int127())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
10
|
|
389
|
|
|
|
*/
|
|
@(require_results) int127 :: proc(gen := context.random_generator) -> (val: i128) { return i128(uint128(gen) << 1 >> 1) }
|
|
|
|
/*
|
|
Generates a random 31 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 31 bit value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is less than or equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int31_max_example :: proc() {
|
|
fmt.println(rand.int31_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
int31_max :: proc(n: i32, gen := context.random_generator) -> (val: i32) {
|
|
if n <= 0 {
|
|
panic("Invalid argument to int31_max")
|
|
}
|
|
if n&(n-1) == 0 {
|
|
return int31(gen) & (n-1)
|
|
}
|
|
max := i32((1<<31) - 1 - (1<<31)%u32(n))
|
|
v := int31(gen)
|
|
for v > max {
|
|
v = int31(gen)
|
|
}
|
|
return v % n
|
|
}
|
|
|
|
/*
|
|
Generates a random 63 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 63 bit value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is less than or equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int63_max_example :: proc() {
|
|
fmt.println(rand.int63_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
int63_max :: proc(n: i64, gen := context.random_generator) -> (val: i64) {
|
|
if n <= 0 {
|
|
panic("Invalid argument to int63_max")
|
|
}
|
|
if n&(n-1) == 0 {
|
|
return int63(gen) & (n-1)
|
|
}
|
|
max := i64((1<<63) - 1 - (1<<63)%u64(n))
|
|
v := int63(gen)
|
|
for v > max {
|
|
v = int63(gen)
|
|
}
|
|
return v % n
|
|
}
|
|
|
|
/*
|
|
Generates a random 127 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 127 bit value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is less than or equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int127_max_example :: proc() {
|
|
fmt.println(rand.int127_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
int127_max :: proc(n: i128, gen := context.random_generator) -> (val: i128) {
|
|
if n <= 0 {
|
|
panic("Invalid argument to int127_max")
|
|
}
|
|
if n&(n-1) == 0 {
|
|
return int127(gen) & (n-1)
|
|
}
|
|
max := i128((1<<127) - 1 - (1<<127)%u128(n))
|
|
v := int127(gen)
|
|
for v > max {
|
|
v = int127(gen)
|
|
}
|
|
return v % n
|
|
}
|
|
|
|
/*
|
|
Generates a random integer value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random integer value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is less than or equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int_max_example :: proc() {
|
|
fmt.println(rand.int_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
int_max :: proc(n: int, gen := context.random_generator) -> (val: int) {
|
|
if n <= 0 {
|
|
panic("Invalid argument to int_max")
|
|
}
|
|
when size_of(int) == 4 {
|
|
return int(int31_max(i32(n), gen))
|
|
} else {
|
|
return int(int63_max(i64(n), gen))
|
|
}
|
|
}
|
|
|
|
/*
|
|
Generates a random 32 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 32 bit value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint32_max_example :: proc() {
|
|
fmt.println(rand.uint32_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
uint32_max :: proc(n: u32, gen := context.random_generator) -> (val: u32) {
|
|
if n == 0 {
|
|
panic("Invalid argument to uint32_max")
|
|
}
|
|
if n & (n - 1) == 0 {
|
|
return uint32(gen) & (n - 1)
|
|
}
|
|
min := (-n) % n
|
|
v := uint32(gen)
|
|
for v < min {
|
|
v = uint32(gen)
|
|
}
|
|
return v % n
|
|
}
|
|
|
|
/*
|
|
Generates a random 64 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 64 bit value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint64_max_example :: proc() {
|
|
fmt.println(rand.uint64_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
uint64_max :: proc(n: u64, gen := context.random_generator) -> (val: u64) {
|
|
if n == 0 {
|
|
panic("Invalid argument to uint64_max")
|
|
}
|
|
if n & (n - 1) == 0 {
|
|
return uint64(gen) & (n - 1)
|
|
}
|
|
min := (-n) % n
|
|
v := uint64(gen)
|
|
for v < min {
|
|
v = uint64(gen)
|
|
}
|
|
return v % n
|
|
}
|
|
|
|
/*
|
|
Generates a random 128 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 128 bit value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint128_max_example :: proc() {
|
|
fmt.println(rand.uint128_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
uint128_max :: proc(n: u128, gen := context.random_generator) -> (val: u128) {
|
|
if n == 0 {
|
|
panic("Invalid argument to uint128_max")
|
|
}
|
|
if n & (n - 1) == 0 {
|
|
return uint128(gen) & (n - 1)
|
|
}
|
|
min := (-n) % n
|
|
v := uint128(gen)
|
|
for v < min {
|
|
v = uint128(gen)
|
|
}
|
|
return v % n
|
|
}
|
|
|
|
/*
|
|
Generates a random integer value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- n: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random integer value in the range `[0, n)`
|
|
|
|
WARNING: Panics if n is equal to 0
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint_max_example :: proc() {
|
|
fmt.println(rand.uint_max(16))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
uint_max :: proc(n: uint, gen := context.random_generator) -> (val: uint) {
|
|
if n <= 0 {
|
|
panic("Invalid argument to uint_max")
|
|
}
|
|
when size_of(int) == 4 {
|
|
return uint(uint32_max(u32(n), gen))
|
|
} else {
|
|
return uint(uint64_max(u64(n), gen))
|
|
}
|
|
}
|
|
|
|
/*
|
|
Generates a random unsigned 32 bit value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 32 bit value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint32_range_example :: proc() {
|
|
fmt.println(rand.uint32_range(5,15))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
uint32_range :: proc(lo, hi: u32, gen := context.random_generator) -> (val: u32) {
|
|
assert(lo < hi, "Invalid arguments to uint32_range: lo must be less than hi")
|
|
range := hi - lo
|
|
if (range & (range - 1)) == 0 {
|
|
return lo + (uint32(gen) & (range - 1))
|
|
}
|
|
threshold := -range % range
|
|
v := uint32(gen)
|
|
for v < threshold {
|
|
v = uint32(gen)
|
|
}
|
|
return lo + (v % range)
|
|
}
|
|
|
|
/*
|
|
Generates a random unsigned 64 bit value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 64 bit value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint64_range_example :: proc() {
|
|
fmt.println(rand.uint64_range(5,15))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
uint64_range :: proc(lo, hi: u64, gen := context.random_generator) -> (val: u64) {
|
|
assert(lo < hi, "Invalid arguments to uint64_range: lo must be less than hi")
|
|
range := hi - lo
|
|
if (range & (range - 1)) == 0 {
|
|
return lo + (uint64(gen) & (range - 1))
|
|
}
|
|
threshold := -range % range
|
|
v := uint64(gen)
|
|
for v < threshold {
|
|
v = uint64(gen)
|
|
}
|
|
return lo + (v % range)
|
|
}
|
|
|
|
/*
|
|
Generates a random unsigned 128 bit value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 128 bit value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint128_range_example :: proc() {
|
|
fmt.println(rand.uint128_range(5,15))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
uint128_range :: proc(lo, hi: u128, gen := context.random_generator) -> (val: u128) {
|
|
assert(lo < hi, "Invalid arguments to uint128_range: lo must be less than hi")
|
|
range := hi - lo
|
|
if (range & (range - 1)) == 0 {
|
|
return lo + (uint128(gen) & (range - 1))
|
|
}
|
|
threshold := -range % range
|
|
v := uint128(gen)
|
|
for v < threshold {
|
|
v = uint128(gen)
|
|
}
|
|
return lo + (v % range)
|
|
}
|
|
|
|
/*
|
|
Generates a random unsigned integer value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random integer value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
uint_range_example :: proc() {
|
|
fmt.println(rand.uint_range(5,15))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
13
|
|
|
|
*/
|
|
@(require_results)
|
|
uint_range :: proc(lo, hi: uint, gen := context.random_generator) -> (val: uint) {
|
|
assert(lo < hi, "Invalid arguments to uint_range: lo must be less than hi")
|
|
when size_of(int) == 4 {
|
|
return uint(uint32_range(u32(lo), u32(hi), gen))
|
|
} else {
|
|
return uint(uint64_range(u64(lo), u64(hi), gen))
|
|
}
|
|
}
|
|
|
|
/*
|
|
Generates a random signed 32 bit value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 32 bit value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int32_range_example :: proc() {
|
|
fmt.println(rand.int32_range(-10,10))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
-9
|
|
|
|
*/
|
|
int32_range :: proc(lo, hi: i32, gen := context.random_generator) -> (val: i32) {
|
|
assert(lo < hi, "Invalid arguments to int32_range: lo must be less than hi")
|
|
range := u32(hi) - u32(lo)
|
|
if (range & (range - 1)) == 0 {
|
|
return lo + i32(uint32(gen) & (range - 1))
|
|
}
|
|
threshold := -range % range
|
|
v := uint32(gen)
|
|
for v < threshold {
|
|
v = uint32(gen)
|
|
}
|
|
return lo + i32(v % range)
|
|
}
|
|
|
|
/*
|
|
Generates a random signed 64 bit value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 64 bit value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int64_range_example :: proc() {
|
|
fmt.println(rand.int64_range(-10,10))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
-9
|
|
|
|
*/
|
|
int64_range :: proc(lo, hi: i64, gen := context.random_generator) -> (val: i64) {
|
|
assert(lo < hi, "Invalid arguments to int64_range: lo must be less than hi")
|
|
range := u64(hi) - u64(lo)
|
|
if (range & (range - 1)) == 0 {
|
|
return lo + i64(uint64(gen) & (range - 1))
|
|
}
|
|
threshold := -range % range
|
|
v := uint64(gen)
|
|
for v < threshold {
|
|
v = uint64(gen)
|
|
}
|
|
return lo + i64(v % range)
|
|
}
|
|
|
|
/*
|
|
Generates a random signed 128 bit value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random 128 bit value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int128_range_example :: proc() {
|
|
fmt.println(rand.int128_range(-10,10))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
-9
|
|
|
|
*/
|
|
int128_range :: proc(lo, hi: i128, gen := context.random_generator) -> (val: i128) {
|
|
assert(lo < hi, "Invalid arguments to int128_range: lo must be less than hi")
|
|
range := u128(hi) - u128(lo)
|
|
if (range & (range - 1)) == 0 {
|
|
return lo + i128(uint128(gen) & (range - 1))
|
|
}
|
|
threshold := -range % range
|
|
v := uint128(gen)
|
|
for v < threshold {
|
|
v = uint128(gen)
|
|
}
|
|
return lo + i128(v % range)
|
|
}
|
|
|
|
/*
|
|
Generates a random signed integer value in the range `[lo, hi)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- lo: The lower bound of the generated number, this value is inclusice
|
|
- hi: The upper bound of the generated number, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random integer value in the range `[lo, hi)`
|
|
|
|
WARNING: Panics if `lo` is greater or equal to `hi`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
int_range_example :: proc() {
|
|
fmt.println(rand.int_range(-10,10))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
6
|
|
-9
|
|
|
|
*/
|
|
@(require_results)
|
|
int_range :: proc(lo, hi: int, gen := context.random_generator) -> (val: int) {
|
|
assert(lo < hi, "Invalid arguments to int_range: lo must be less than hi")
|
|
when size_of(int) == 4 {
|
|
return int(int32_range(i32(lo), i32(hi), gen))
|
|
} else {
|
|
return int(int64_range(i64(lo), i64(hi), gen))
|
|
}
|
|
}
|
|
|
|
/*
|
|
Generates a random double floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Returns:
|
|
- val: A random double floating point value in the range `[0, 1)`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
float64_example :: proc() {
|
|
fmt.println(rand.float64())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
0.043
|
|
0.511
|
|
|
|
*/
|
|
@(require_results) float64 :: proc(gen := context.random_generator) -> (val: f64) { return f64(int63_max(1<<53, gen)) / (1 << 53) }
|
|
|
|
/*
|
|
Generates a random single floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Returns:
|
|
- val: A random single floating point value in the range `[0, 1)`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
float32_example :: proc() {
|
|
fmt.println(rand.float32())
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
0.043
|
|
0.511
|
|
|
|
*/
|
|
@(require_results) float32 :: proc(gen := context.random_generator) -> (val: f32) { return f32(int31_max(1<<24, gen)) / (1 << 24) }
|
|
|
|
/*
|
|
Generates a random double floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
WARNING: Panics if `high < low`
|
|
|
|
Inputs:
|
|
- low: The lower bounds of the value, this value is inclusive
|
|
- high: The upper bounds of the value, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random double floating point value in the range [low, high)
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
float64_range_example :: proc() {
|
|
fmt.println(rand.float64_range(-10, 300))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
15.312
|
|
273.15
|
|
|
|
*/
|
|
@(require_results) float64_range :: proc(low, high: f64, gen := context.random_generator) -> (val: f64) {
|
|
assert(low <= high, "low must be lower than or equal to high")
|
|
val = (high-low)*float64(gen) + low
|
|
if val >= high {
|
|
val = max(low, high * (1 - math.F64_EPSILON))
|
|
}
|
|
return
|
|
}
|
|
|
|
/*
|
|
Generates a random single floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- low: The lower bounds of the value, this value is inclusive
|
|
- high: The upper bounds of the value, this value is exclusive
|
|
|
|
Returns:
|
|
- val: A random single floating point value in the range [low, high)
|
|
|
|
WARNING: Panics if `high < low`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
float32_range_example :: proc() {
|
|
fmt.println(rand.float32_range(-10, 300))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
15.312
|
|
273.15
|
|
|
|
*/
|
|
@(require_results) float32_range :: proc(low, high: f32, gen := context.random_generator) -> (val: f32) {
|
|
assert(low <= high, "low must be lower than or equal to high")
|
|
val = (high-low)*float32(gen) + low
|
|
if val >= high {
|
|
val = max(low, high * (1 - math.F32_EPSILON))
|
|
}
|
|
return
|
|
}
|
|
|
|
/*
|
|
Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value.
|
|
|
|
Inputs:
|
|
- p: The byte slice to fill
|
|
|
|
Returns:
|
|
- n: The number of bytes generated
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
read_example :: proc() {
|
|
data: [8]byte
|
|
n := rand.read(data[:])
|
|
fmt.println(n)
|
|
fmt.println(data)
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
8
|
|
[32, 4, 59, 7, 1, 2, 2, 119]
|
|
|
|
*/
|
|
@(require_results)
|
|
read :: proc(p: []byte, gen := context.random_generator) -> (n: int) {
|
|
if !runtime.random_generator_read_bytes(gen, p) {return 0}
|
|
return len(p)
|
|
}
|
|
|
|
/*
|
|
Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
|
|
|
|
*Allocates Using Provided Allocator*
|
|
|
|
Inputs:
|
|
- n: The size of the created slice
|
|
- allocator: (default: context.allocator)
|
|
|
|
Returns:
|
|
- res: A slice filled with random values
|
|
- err: An allocator error if one occured, `nil` otherwise
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:mem"
|
|
import "core:fmt"
|
|
|
|
perm_example :: proc() -> (err: mem.Allocator_Error) {
|
|
data := rand.perm(4) or_return
|
|
fmt.println(data)
|
|
defer delete(data, context.allocator)
|
|
|
|
return
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
[7201011, 3, 9123, 231131]
|
|
[19578, 910081, 131, 7]
|
|
|
|
*/
|
|
@(require_results)
|
|
perm :: proc(n: int, allocator := context.allocator, gen := context.random_generator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error {
|
|
m := make([]int, n, allocator) or_return
|
|
for i := 0; i < n; i += 1 {
|
|
j := int_max(i+1, gen)
|
|
m[i] = m[j]
|
|
m[j] = i
|
|
}
|
|
return m, {}
|
|
}
|
|
|
|
/*
|
|
Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- array: The slice to randomize
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
shuffle_example :: proc() {
|
|
data: [4]int = { 1, 2, 3, 4 }
|
|
fmt.println(data) // the contents are in order
|
|
rand.shuffle(data[:])
|
|
fmt.println(data) // the contents have been shuffled
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
[1, 2, 3, 4]
|
|
[2, 4, 3, 1]
|
|
|
|
*/
|
|
shuffle :: proc(array: $T/[]$E, gen := context.random_generator) {
|
|
n := i64(len(array))
|
|
if n < 2 {
|
|
return
|
|
}
|
|
|
|
i := n - 1
|
|
for ; i > (1<<31 - 2); i -= 1 {
|
|
j := int63_max(i + 1, gen)
|
|
array[i], array[j] = array[j], array[i]
|
|
}
|
|
|
|
for ; i > 0; i -= 1 {
|
|
j := int31_max(i32(i + 1), gen)
|
|
array[i], array[j] = array[j], array[i]
|
|
}
|
|
}
|
|
|
|
/*
|
|
Returns a random element from the provided slice. If no generator is provided the global random number generator will be used.
|
|
|
|
Inputs:
|
|
- array: The slice to choose an element from
|
|
|
|
Returns:
|
|
- res: A random element from `array`
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
choice_example :: proc() {
|
|
data: [4]int = { 1, 2, 3, 4 }
|
|
fmt.println(rand.choice(data[:]))
|
|
fmt.println(rand.choice(data[:]))
|
|
fmt.println(rand.choice(data[:]))
|
|
fmt.println(rand.choice(data[:]))
|
|
}
|
|
|
|
Possible Output:
|
|
|
|
3
|
|
2
|
|
2
|
|
4
|
|
|
|
*/
|
|
@(require_results)
|
|
choice :: proc(array: $T/[]$E, gen := context.random_generator) -> (res: E) {
|
|
n := i64(len(array))
|
|
if n < 1 {
|
|
return E{}
|
|
}
|
|
return array[int63_max(n, gen)]
|
|
}
|
|
|
|
|
|
@(require_results)
|
|
choice_enum :: proc($T: typeid, gen := context.random_generator) -> T where intrinsics.type_is_enum(T) {
|
|
when size_of(T) <= 8 && len(T) == cap(T) {
|
|
when intrinsics.type_is_unsigned(intrinsics.type_core_type(T)) &&
|
|
u64(max(T)) > u64(max(i64)) {
|
|
i := uint64(gen) % u64(len(T))
|
|
i += u64(min(T))
|
|
return T(i)
|
|
} else {
|
|
i := int63_max(i64(len(T)), gen)
|
|
i += i64(min(T))
|
|
return T(i)
|
|
}
|
|
} else {
|
|
values := runtime.type_info_base(type_info_of(T)).variant.(runtime.Type_Info_Enum).values
|
|
return T(choice(values))
|
|
}
|
|
}
|
|
|
|
/*
|
|
Returns a random *set* bit from the provided `bit_set`.
|
|
|
|
Inputs:
|
|
- set: The `bit_set` to choose a random set bit from
|
|
|
|
Returns:
|
|
- res: The randomly selected bit, or the zero value if `ok` is `false`
|
|
- ok: Whether the bit_set was not empty and thus `res` is actually a random set bit
|
|
|
|
Example:
|
|
import "core:math/rand"
|
|
import "core:fmt"
|
|
|
|
choice_bit_set_example :: proc() {
|
|
Flags :: enum {
|
|
A,
|
|
B = 10,
|
|
C,
|
|
}
|
|
|
|
fmt.println(rand.choice_bit_set(bit_set[Flags]{}))
|
|
fmt.println(rand.choice_bit_set(bit_set[Flags]{.B}))
|
|
fmt.println(rand.choice_bit_set(bit_set[Flags]{.B, .C}))
|
|
fmt.println(rand.choice_bit_set(bit_set[0..<15]{5, 1, 4}))
|
|
}
|
|
|
|
Possible Output:
|
|
A false
|
|
B true
|
|
C true
|
|
5 true
|
|
*/
|
|
@(require_results)
|
|
choice_bit_set :: proc(set: $T/bit_set[$E], gen := context.random_generator) -> (res: E, ok: bool) {
|
|
total_set := card(set)
|
|
if total_set == 0 {
|
|
return {}, false
|
|
}
|
|
|
|
target := int_max(total_set, gen)
|
|
|
|
for value in set {
|
|
if target == 0 {
|
|
return value, true
|
|
}
|
|
target -= 1
|
|
}
|
|
|
|
return {}, false
|
|
}
|