mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-03 05:08:14 +00:00
Document core:math/rand and add 'possible output'
Possible output allows us to just type check a test and have some sort of output field in the docs but not actually verify it matches stdout
This commit is contained in:
+636
-24
@@ -1,6 +1,10 @@
|
|||||||
|
/*
|
||||||
|
Package core:math/rand implements various random number generators
|
||||||
|
*/
|
||||||
package rand
|
package rand
|
||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
Rand :: struct {
|
Rand :: struct {
|
||||||
state: u64,
|
state: u64,
|
||||||
@@ -12,17 +16,82 @@ Rand :: struct {
|
|||||||
@(private)
|
@(private)
|
||||||
global_rand := create(u64(intrinsics.read_cycle_counter()))
|
global_rand := create(u64(intrinsics.read_cycle_counter()))
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets the seed used by the global random number generator.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- seed: The seed value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
set_global_seed_example :: proc() {
|
||||||
|
rand.set_global_seed(1)
|
||||||
|
fmt.println(rand.uint64())
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
*/
|
||||||
set_global_seed :: proc(seed: u64) {
|
set_global_seed :: proc(seed: u64) {
|
||||||
init(&global_rand, seed)
|
init(&global_rand, seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates a new random number generator.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- seed: The seed value to create the random number generator with
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- res: The created random number generator
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
create_example :: proc() {
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.uint64(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
create :: proc(seed: u64) -> Rand {
|
create :: proc(seed: u64) -> (res: Rand) {
|
||||||
r: Rand
|
r: Rand
|
||||||
init(&r, seed)
|
init(&r, seed)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialises a random number generator.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to initialise
|
||||||
|
- seed: The seed value to initialise this random number generator
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
init_example :: proc() {
|
||||||
|
my_rand: rand.Rand
|
||||||
|
rand.init(&my_rand, 1)
|
||||||
|
fmt.println(rand.uint64(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
*/
|
||||||
init :: proc(r: ^Rand, seed: u64) {
|
init :: proc(r: ^Rand, seed: u64) {
|
||||||
r.state = 0
|
r.state = 0
|
||||||
r.inc = (seed << 1) | 1
|
r.inc = (seed << 1) | 1
|
||||||
@@ -31,6 +100,35 @@ init :: proc(r: ^Rand, seed: u64) {
|
|||||||
_random(r)
|
_random(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialises a random number generator to use the system random number generator.
|
||||||
|
The system random number generator is platform specific.
|
||||||
|
On `linux` refer to the `getrandom` syscall.
|
||||||
|
On `darwin` refer to `getentropy`.
|
||||||
|
On `windows` refer to `BCryptGenRandom`.
|
||||||
|
|
||||||
|
All other platforms wi
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use the system random number generator
|
||||||
|
|
||||||
|
WARNING: Panics if the system is not either `windows`, `darwin` or `linux`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
init_as_system_example :: proc() {
|
||||||
|
my_rand: rand.Rand
|
||||||
|
rand.init_as_system(&my_rand)
|
||||||
|
fmt.println(rand.uint64(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
*/
|
||||||
init_as_system :: proc(r: ^Rand) {
|
init_as_system :: proc(r: ^Rand) {
|
||||||
if !#defined(_system_random) {
|
if !#defined(_system_random) {
|
||||||
panic(#procedure + " is not supported on this platform yet")
|
panic(#procedure + " is not supported on this platform yet")
|
||||||
@@ -61,18 +159,99 @@ _random :: proc(r: ^Rand) -> u32 {
|
|||||||
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
|
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
/*
|
||||||
uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r) }
|
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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random unsigned 32 bit value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
uint32_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.uint32())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.uint32(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
389
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
uint64 :: proc(r: ^Rand = nil) -> u64 {
|
uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return _random(r) }
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random unsigned 64 bit value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
uint64_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.uint64())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.uint64(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
389
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results)
|
||||||
|
uint64 :: proc(r: ^Rand = nil) -> (val: u64) {
|
||||||
a := u64(_random(r))
|
a := u64(_random(r))
|
||||||
b := u64(_random(r))
|
b := u64(_random(r))
|
||||||
return (a<<32) | b
|
return (a<<32) | b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random unsigned 128 bit value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
uint128_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.uint128())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.uint128(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
389
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
uint128 :: proc(r: ^Rand = nil) -> u128 {
|
uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
|
||||||
a := u128(_random(r))
|
a := u128(_random(r))
|
||||||
b := u128(_random(r))
|
b := u128(_random(r))
|
||||||
c := u128(_random(r))
|
c := u128(_random(r))
|
||||||
@@ -80,12 +259,126 @@ uint128 :: proc(r: ^Rand = nil) -> u128 {
|
|||||||
return (a<<96) | (b<<64) | (c<<32) | d
|
return (a<<96) | (b<<64) | (c<<32) | d
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results) int31 :: proc(r: ^Rand = nil) -> i32 { return i32(uint32(r) << 1 >> 1) }
|
/*
|
||||||
@(require_results) int63 :: proc(r: ^Rand = nil) -> i64 { return i64(uint64(r) << 1 >> 1) }
|
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.
|
||||||
@(require_results) int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) }
|
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random 31 bit value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
int31_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.int31())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.int31(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
389
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random 63 bit value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
int63_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.int63())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.int63(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
389
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random 127 bit value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
int127_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.int127())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.int127(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
10
|
||||||
|
389
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random 31 bit value in the range `(0, n]`
|
||||||
|
|
||||||
|
WARNING: Panics if n is less than 0
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
int31_max_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.int31_max(16))
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.int31_max(1024, &my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
6
|
||||||
|
500
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
|
int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int31_max")
|
panic("Invalid argument to int31_max")
|
||||||
}
|
}
|
||||||
@@ -99,9 +392,38 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
|
|||||||
}
|
}
|
||||||
return v % n
|
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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random 63 bit value in the range `(0, n]`
|
||||||
|
|
||||||
|
WARNING: Panics if n is less than 0
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
int63_max_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.int63_max(16))
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.int63_max(1024, &my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
6
|
||||||
|
500
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
|
int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int63_max")
|
panic("Invalid argument to int63_max")
|
||||||
}
|
}
|
||||||
@@ -115,9 +437,38 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
|
|||||||
}
|
}
|
||||||
return v % n
|
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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random 127 bit value in the range `(0, n]`
|
||||||
|
|
||||||
|
WARNING: Panics if n is less than 0
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
int127_max_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.int127_max(16))
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.int127_max(1024, &my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
6
|
||||||
|
500
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
|
int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int127_max")
|
panic("Invalid argument to int127_max")
|
||||||
}
|
}
|
||||||
@@ -131,9 +482,38 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
|
|||||||
}
|
}
|
||||||
return v % n
|
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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random integer value in the range `(0, n]`
|
||||||
|
|
||||||
|
WARNING: Panics if n is less than 0
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
int_max_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.int_max(16))
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.int_max(1024, &my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
6
|
||||||
|
500
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int_max :: proc(n: int, r: ^Rand = nil) -> int {
|
int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int_max")
|
panic("Invalid argument to int_max")
|
||||||
}
|
}
|
||||||
@@ -144,14 +524,153 @@ int_max :: proc(n: int, r: ^Rand = nil) -> int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uniform random distribution [0, 1)
|
/*
|
||||||
@(require_results) float64 :: proc(r: ^Rand = nil) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53) }
|
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.
|
||||||
// Uniform random distribution [0, 1)
|
|
||||||
@(require_results) float32 :: proc(r: ^Rand = nil) -> f32 { return f32(float64(r)) }
|
|
||||||
|
|
||||||
@(require_results) float64_range :: proc(lo, hi: f64, r: ^Rand = nil) -> f64 { return (hi-lo)*float64(r) + lo }
|
Inputs:
|
||||||
@(require_results) float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo }
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random double floating point value in the range `(0, 1]`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
float64_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.float64())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.float64(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
0.043
|
||||||
|
0.511
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random single floating point value in the range `(0, 1]`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
float32_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.float32())
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.float32(&my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
0.043
|
||||||
|
0.511
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(float64(r)) }
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- low: The lower bounds of the value, this value is inclusive
|
||||||
|
- high: The upper bounds of the value, this value is exclusive
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
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() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.float64_range(-10, 300))
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.float64_range(600, 900, &my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
15.312
|
||||||
|
673.130
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { return (high-low)*float64(r) + low }
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- val: A random single floating point value in the range `(low, high]`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
float32_range_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
fmt.println(rand.float32_range(-10, 300))
|
||||||
|
// Using local random number generator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
fmt.println(rand.float32_range(600, 900, &my_rand))
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
15.312
|
||||||
|
673.130
|
||||||
|
|
||||||
|
*/
|
||||||
|
@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { return (high-low)*float32(r) + low }
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- p: The byte slice to fill
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- n: The number of bytes generated
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
read_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
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)
|
@(require_results)
|
||||||
read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
|
read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
|
||||||
pos := i8(0)
|
pos := i8(0)
|
||||||
@@ -168,19 +687,81 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n)
|
/*
|
||||||
|
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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
- 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) {
|
||||||
|
// Using the global random number generator and using the context allocator
|
||||||
|
data := rand.perm(4) or_return
|
||||||
|
fmt.println(data)
|
||||||
|
defer delete(data, context.allocator)
|
||||||
|
|
||||||
|
// Using local random number generator and temp allocator
|
||||||
|
my_rand := rand.create(1)
|
||||||
|
data_tmp := rand.perm(4, &my_rand, context.temp_allocator) or_return
|
||||||
|
fmt.println(data_tmp)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Possible Output:
|
||||||
|
|
||||||
|
[7201011, 3, 9123, 231131]
|
||||||
|
[19578, 910081, 131, 7]
|
||||||
|
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int {
|
perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error {
|
||||||
m := make([]int, n, allocator)
|
m := make([]int, n, allocator) or_return
|
||||||
for i := 0; i < n; i += 1 {
|
for i := 0; i < n; i += 1 {
|
||||||
j := int_max(i+1, r)
|
j := int_max(i+1, r)
|
||||||
m[i] = m[j]
|
m[i] = m[j]
|
||||||
m[j] = i
|
m[j] = i
|
||||||
}
|
}
|
||||||
return m
|
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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
shuffle_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
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, r: ^Rand = nil) {
|
shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
|
||||||
n := i64(len(array))
|
n := i64(len(array))
|
||||||
if n < 2 {
|
if n < 2 {
|
||||||
@@ -193,7 +774,38 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a random element from the given slice
|
/*
|
||||||
|
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
|
||||||
|
- r: The random number generator to use, or nil for the global generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- res: A random element from `array`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
choice_example :: proc() {
|
||||||
|
// Using the global random number generator
|
||||||
|
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)
|
@(require_results)
|
||||||
choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
|
choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
|
||||||
n := i64(len(array))
|
n := i64(len(array))
|
||||||
@@ -201,4 +813,4 @@ choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
|
|||||||
return E{}
|
return E{}
|
||||||
}
|
}
|
||||||
return array[int63_max(n, r)]
|
return array[int63_max(n, r)]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Example_Test :: struct {
|
|||||||
package_name: string,
|
package_name: string,
|
||||||
example_code: []string,
|
example_code: []string,
|
||||||
expected_output: []string,
|
expected_output: []string,
|
||||||
|
skip_output_check: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
g_header: ^doc.Header
|
g_header: ^doc.Header
|
||||||
@@ -145,6 +146,7 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
|
|||||||
curr_block_kind := Block_Kind.Other
|
curr_block_kind := Block_Kind.Other
|
||||||
start := 0
|
start := 0
|
||||||
|
|
||||||
|
found_possible_output: bool
|
||||||
example_block: Block // when set the kind should be Example
|
example_block: Block // when set the kind should be Example
|
||||||
output_block: Block // when set the kind should be Output
|
output_block: Block // when set the kind should be Output
|
||||||
// rely on zii that the kinds have not been set
|
// rely on zii that the kinds have not been set
|
||||||
@@ -178,10 +180,16 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
|
|||||||
switch {
|
switch {
|
||||||
case strings.has_prefix(line, "Example:"): next_block_kind = .Example
|
case strings.has_prefix(line, "Example:"): next_block_kind = .Example
|
||||||
case strings.has_prefix(line, "Output:"): next_block_kind = .Output
|
case strings.has_prefix(line, "Output:"): next_block_kind = .Output
|
||||||
|
case strings.has_prefix(line, "Possible Output:"):
|
||||||
|
next_block_kind = .Output
|
||||||
|
found_possible_output = true
|
||||||
}
|
}
|
||||||
case .Example:
|
case .Example:
|
||||||
switch {
|
switch {
|
||||||
case strings.has_prefix(line, "Output:"): next_block_kind = .Output
|
case strings.has_prefix(line, "Output:"): next_block_kind = .Output
|
||||||
|
case strings.has_prefix(line, "Possible Output:"):
|
||||||
|
next_block_kind = .Output
|
||||||
|
found_possible_output = true
|
||||||
case ! (text == "" || strings.has_prefix(line, "\t")): next_block_kind = .Other
|
case ! (text == "" || strings.has_prefix(line, "\t")): next_block_kind = .Other
|
||||||
}
|
}
|
||||||
case .Output:
|
case .Output:
|
||||||
@@ -219,8 +227,9 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
|
|||||||
{
|
{
|
||||||
// Output block starts with
|
// Output block starts with
|
||||||
// `Output:` and a number of white spaces,
|
// `Output:` and a number of white spaces,
|
||||||
|
// `Possible Output:` and a number of white spaces,
|
||||||
lines := &output_block.lines
|
lines := &output_block.lines
|
||||||
for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Output:")) {
|
for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Output:") || strings.has_prefix(lines[0], "Possible Output:")) {
|
||||||
lines^ = lines[1:]
|
lines^ = lines[1:]
|
||||||
}
|
}
|
||||||
// Additionally we need to strip all empty lines at the end of output to not include those in the expected output
|
// Additionally we need to strip all empty lines at the end of output to not include those in the expected output
|
||||||
@@ -240,6 +249,7 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
|
|||||||
package_name = package_name,
|
package_name = package_name,
|
||||||
example_code = example_block.lines,
|
example_code = example_block.lines,
|
||||||
expected_output = output_block.lines,
|
expected_output = output_block.lines,
|
||||||
|
skip_output_check = found_possible_output,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,25 +414,29 @@ main :: proc() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.sbprintf(&test_runner, "\t%v_%v()\n", test.package_name, code_test_name)
|
// NOTE: packages like 'rand' are random by nature, in these cases we cannot verify against the output string
|
||||||
fmt.sbprintf(&test_runner, "\t_check(%q, `", code_test_name)
|
// in these cases we just mark the output as 'Possible Output' and we simply skip checking against the output
|
||||||
had_line_error: bool
|
if ! test.skip_output_check {
|
||||||
for line in test.expected_output {
|
fmt.sbprintf(&test_runner, "\t%v_%v()\n", test.package_name, code_test_name)
|
||||||
// NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of `
|
fmt.sbprintf(&test_runner, "\t_check(%q, `", code_test_name)
|
||||||
// I don't think any examples would really need this specific character so let's just make it forbidden and change
|
had_line_error: bool
|
||||||
// in the future if we really need to
|
for line in test.expected_output {
|
||||||
if strings.contains_rune(line, '`') {
|
// NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of `
|
||||||
fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name)
|
// I don't think any examples would really need this specific character so let's just make it forbidden and change
|
||||||
g_bad_doc = true
|
// in the future if we really need to
|
||||||
had_line_error = true
|
if strings.contains_rune(line, '`') {
|
||||||
|
fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name)
|
||||||
|
g_bad_doc = true
|
||||||
|
had_line_error = true
|
||||||
|
}
|
||||||
|
strings.write_string(&test_runner, line)
|
||||||
|
strings.write_string(&test_runner, "\n")
|
||||||
}
|
}
|
||||||
strings.write_string(&test_runner, line)
|
if had_line_error {
|
||||||
strings.write_string(&test_runner, "\n")
|
continue
|
||||||
|
}
|
||||||
|
strings.write_string(&test_runner, "`)\n")
|
||||||
}
|
}
|
||||||
if had_line_error {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
strings.write_string(&test_runner, "`)\n")
|
|
||||||
save_path := fmt.tprintf("verify/test_%v_%v.odin", test.package_name, code_test_name)
|
save_path := fmt.tprintf("verify/test_%v_%v.odin", test.package_name, code_test_name)
|
||||||
|
|
||||||
test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != 0 {
|
test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user