std/random
Random, a seedable and splittable SplitMix64 generator that is a value - the same seed makes the same numbers on every machine, with integers of a range, floats, shuffling, choice, sampling and independent splits.
The generated reference of std/random has every public construct with its signature, its doc comment and its examples.
std/random makes pseudo-random numbers from a generator that is a value. Random.seeded seed starts one; every draw
advances it, so it lives in a var; the same seed makes the same numbers on every machine, in the VM and in a native
binary, because it is ordinary TorbScript with no native. A computation that gives a split of its generator to each of
its parts makes the same numbers whichever part runs first, which is what a reproducible test, a simulation and
parallel training need (RANDOM.md).
The algorithm is SplitMix64 and its output for a seed is stable: seed 0 begins 16294208416658607535,
7960286522194355700, 487617019471545679, and seed 1234567 begins 6457827717110365317, 3203168211198807973,
9817491932198370423, the published vectors. The mapping to integers (rejection sampling, so there is no modulo bias),
to floats (the top 53 bits over 2^53, in [0, 1)) and the order of a shuffle are part of that promise. The package
is not for cryptography: SplitMix64 can be recovered from a few outputs. A key, a nonce or a token is made from
Entropy of std/os, and Random.seeded Entropy.int64() is the unpredictable seed.
Import#
use Random from "std/random"use Random from "std/random"
var source = Random.seeded 1234567
print source.uint64()Declarations#
Random#
type Random {
static fn seeded(seed: Int): Self
var fn uint64(): UInt64
var fn float(): Float64
var fn int(range: Range<Int>): Int
var fn split(): Self
var fn shuffled<Item>(items: List<Item>): List<Item>
var fn shuffle<Item>(var items: List<Item>)
var fn choice<Item>(items: List<Item>): Item?
var fn sample<Item>(items: List<Item>, count: Int): List<Item>
}Random.seeded(seed) is the generator of a seed; a negative seed is its two's complement, so every Int is a distinct
state. uint64 is the next 64 bits and the source of every other draw. float is a Float64 in [0, 1) with 53
random bits. int(range) is a uniform Int of a range, 1..6 or 1..=6; it panics on an empty range, and
Int.minimum..=Int.maximum is the whole range of an Int.
use Random from "std/random"
var source = Random.seeded 42
const roll = source.int(1..=6)
const fraction = source.float()
print roll
print fractionSplitting#
split answers a new, independent generator and advances the receiver. The child starts from the parent's next output
with a gamma of its own, as SplittableRandom of the JDK does, so the parent and the child do not repeat each other's
numbers.
use Random from "std/random"
var parent = Random.seeded 42
var left = parent.split()
var right = parent.split()
print left.uint64()
print right.uint64()Shuffling, choice and sampling#
shuffled(items) is a new list of the same items in random order (Fisher-Yates) and shuffle does it to a var
list in place. choice(items) is one item, or None for an empty list. sample(items, count) is count distinct
positions of the list, in random order; it panics when count is negative or more than the list holds.
use Random from "std/random"
var source = Random.seeded 42
const mixed = source.shuffled([1, 2, 3, 4, 5])
const picked = source.sample([1, 2, 3, 4, 5], 2)
print mixed
print pickedPitfalls#
- Drawing changes the generator, so it has to be a
var, and a copy of it repeats the original: copy it only to replay a sequence, andsplitit to make a second one. - A seed is not a secret. Anything that has to resist a guess takes its bytes from
Entropy. - Normal and the other continuous distributions are not here; they wait for
std/statistics.