123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836 |
- /*
- Package core:math/rand implements various random number generators
- */
- package rand
- import "core:intrinsics"
- import "core:math"
- import "core:mem"
- Rand :: struct {
- state: u64,
- inc: u64,
- is_system: bool,
- }
- @(private)
- 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) {
- 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)
- create :: proc(seed: u64) -> (res: Rand) {
- r: Rand
- init(&r, seed)
- 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) {
- r.state = 0
- r.inc = (seed << 1) | 1
- _random_u64(r)
- r.state += seed
- _random_u64(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 are not supported
- 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) {
- if !#defined(_system_random) {
- panic(#procedure + " is not supported on this platform yet")
- }
- r.state = 0
- r.inc = 0
- r.is_system = true
- }
- @(private)
- _random_u64 :: proc(r: ^Rand) -> u64 {
- r := r
- if r == nil {
- r = &global_rand
- }
- when #defined(_system_random) {
- if r.is_system {
- return _system_random()
- }
- }
- old_state := r.state
- r.state = old_state * 6364136223846793005 + (r.inc|1)
- xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081
- rot := (old_state >> 59)
- return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63))
- }
- /*
- 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)
- uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return u32(_random_u64(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) { return _random_u64(r) }
- /*
- 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)
- uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
- a := u128(_random_u64(r))
- b := u128(_random_u64(r))
- 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.
- 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)
- int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
- if n <= 0 {
- panic("Invalid argument to int31_max")
- }
- if n&(n-1) == 0 {
- return int31(r) & (n-1)
- }
- max := i32((1<<31) - 1 - (1<<31)%u32(n))
- v := int31(r)
- for v > max {
- v = int31(r)
- }
- 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)
- int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
- if n <= 0 {
- panic("Invalid argument to int63_max")
- }
- if n&(n-1) == 0 {
- return int63(r) & (n-1)
- }
- max := i64((1<<63) - 1 - (1<<63)%u64(n))
- v := int63(r)
- for v > max {
- v = int63(r)
- }
- 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)
- int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
- if n <= 0 {
- panic("Invalid argument to int127_max")
- }
- if n&(n-1) == 0 {
- return int127(r) & (n-1)
- }
- max := i128((1<<127) - 1 - (1<<127)%u128(n))
- v := int127(r)
- for v > max {
- v = int127(r)
- }
- 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)
- int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
- if n <= 0 {
- panic("Invalid argument to int_max")
- }
- when size_of(int) == 4 {
- return int(int31_max(i32(n), r))
- } else {
- return int(int63_max(i64(n), r))
- }
- }
- /*
- 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.
- Inputs:
- - 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(int31_max(1<<24, r)) / (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
- - 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) {
- assert(low <= high, "low must be lower than or equal to high")
- val = (high-low)*float64(r) + 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
- - 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)
- WARNING: Panics if `high < low`
- 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) {
- assert(low <= high, "low must be lower than or equal to high")
- val = (high-low)*float32(r) + 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
- - 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)
- read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
- pos := i8(0)
- val := i64(0)
- for n = 0; n < len(p); n += 1 {
- if pos == 0 {
- val = int63(r)
- pos = 7
- }
- p[n] = byte(val)
- val >>= 8
- pos -= 1
- }
- return
- }
- /*
- 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)
- perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> (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, r)
- 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
- - 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) {
- n := i64(len(array))
- if n < 2 {
- return
- }
- for i := i64(0); i < n; i += 1 {
- j := int63_max(n, r)
- 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
- - 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)
- choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
- n := i64(len(array))
- if n < 1 {
- return E{}
- }
- return array[int63_max(n, r)]
- }
|