Random Numbers
● Intermediate3 minBefore this: FunctionsSpec 14.15
std.random gives random whole numbers, picks and shuffles. Its numbers are safe for passwords and keys, unless a block asks for repeatable ones from a seed.
use std.random
fn roll() -> Int uses Random {
random.int(1, 7)
}
fn main() {
let rolls: [Int] = []
for _ in 0..1_000 {
rolls.push(roll())
}
print("every roll from 1 to 6: {rolls.all(r => 1 <= r <= 6)}")
print("all six faces came up: {[1, 2, 3, 4, 5, 6].all(face => rolls.contains(face))}")
}The program ran and printed:
kavach run dice.kav
every roll from 1 to 6: trueall six faces came up: true
random.int(1, 7) gives 1 to 6: the end is left out, as in 1..7. The program checks its own rolls, because random output can't be written down in advance.
use std.random
fn main() {
const names = ["Asha", "Omar", "Zoe", "Ravi"]
const winner = random.pick(names) ?? "nobody"
print("the winner is one of them: {names.contains(winner)}")
const order = random.shuffle(names)
print("same names, new order: {order.sort() == names.sort()}")
print("a token of 16 bytes: {random.bytes(16).len()}")
}The program ran and printed:
kavach run pick.kav
the winner is one of them: truesame names, new order: truea token of 16 bytes: 16
| Function | Gives |
|---|---|
random.int(from, until) -> Int | A whole number from from up to, not including, until; each equally likely. until must be greater than from (a require) |
random.float() -> Float | A number from 0.0 up to, not including, 1.0 |
random.bool() -> Bool | true or false, each half the time |
random.pick<T>(items) -> T? | One of items, each equally likely; none when there are none |
random.shuffle<T>(items) -> [T] | A copy of items in a random order, every order equally likely |
random.bytes(n) -> Bytes | n random bytes. n is from 0 to 65,536 (a require), as in browsers' crypto.getRandomValues; for more, call it again |
Every function needs uses Random. Under kavach test, random numbers come from the test run's seed instead, so a failing run can be repeated exactly.
Seeded
random.seeded(seed) { … } runs its block with every std.random function drawing from seed instead of the system. The same seed gives the same numbers, on every machine and in every version of Kavach: for simulations, generated worlds and games whose players must all see the same thing.
use std.random
fn world(seed: Int) -> [Int] uses Random {
random.seeded(seed) {
[random.int(0, 100), random.int(0, 100), random.int(0, 100)]
}
}
fn main() uses Random {
print(world(7))
print(world(7))
print(world(8))
print(world(7) == world(7))
}The program ran and printed:
kavach run seeded.kav
[86, 74, 30][86, 74, 30][91, 42, 50]true
- These numbers are not safe for keys, tokens or passwords: anyone who knows the seed knows the numbers.
uses Randomis still needed. Underkavach test, the seed wins over the test run's.- Seeds nest: an inner
seededblock draws from its own seed, and the outer one goes on where it left off. - The seed belongs to the task running the block. A task spawned inside it draws from the system, since tasks may take turns in different orders on different machines.
- The numbers come from xoshiro256**, its state made from the seed by SplitMix64, as their published versions make it.
Limits and sizes
| What | Limit or size | Source |
|---|---|---|
random.bytes(n) | n from 0 to 65,536 per call | 15-random.md |
Every limit in Kavach, on one page: Limits and Sizes.