std.rand
std.rand is a pseudorandom number generator, added in 1.4.0. It is xoshiro256** (D. Blackman and S. Vigna) over a heap-allocated Rng you mint with rng_new and free with free. The seed expands through splitmix64 first, so even a thin seed like 0 or 1 lands the state well away from the all-zero fixed point. The module lives at lib/std/rand.dusk.
@import std.randImported names are flat: after @import std.rand you call rng_new, rng_next, and the rest with no prefix. See stdlib overview for how imports work in general.
The generator
Section titled “The generator”Rng holds the four 64-bit state words xoshiro256** advances on every draw:
export struct Rng { s0: int64, s1: int64, s2: int64, s3: int64,}You never touch the fields directly. Build a generator on the heap with rng_new, pass it by pointer so each draw advances the same state, and free it with the ordinary free when you are done.
Functions
Section titled “Functions”| Function | Description |
|---|---|
rng_new(seed: int64) -> *Rng | A fresh generator seeded from seed, expanded through splitmix64. The caller owns the pointer. |
rng_next(r: *Rng) -> int64 | The next raw 64-bit word, advancing r’s state in place. |
rng_range(r: *Rng, lo: int64, hi: int64) -> int64 | A draw narrowed to [lo, hi). Returns lo when lo >= hi. |
rng_float(r: *Rng) -> float64 | A draw narrowed to a [0, 1) float64. |
shuffle(r: *Rng, xs: int64[]) -> void | Fisher-Yates in place over an int64[]. |
rng_seed_os() -> int64 | A seed folded from eight bytes of kernel entropy through getrandom. |
rng_next is the raw draw; the other draw functions are built on it. rng_range folds off the sign bit before it takes a remainder, so a bounded draw never carries a negative sign into the result; a range with lo >= hi has no value to draw, so it returns lo rather than faulting. rng_float spends the top 53 bits of a draw, the standard construction that fills every mantissa bit evenly. shuffle walks the array from the last index down, swapping each element with a uniformly drawn earlier one; the slice binding needs no mut, since the swaps write the buffer the slice views, not the binding.
Seeding
Section titled “Seeding”rng_new takes any int64. A fixed seed makes the whole sequence deterministic, which is what you want for a test or a reproducible run. When you want unpredictability instead, seed from the OS:
r: *Rng = rng_new(rng_seed_os())rng_seed_os folds eight bytes of kernel entropy from getrandom into a seed. It does not wire true randomness into the generator itself; the generator stays deterministic in its seed, and rng_seed_os just picks that seed for you. A short read is vanishingly unlikely for a request this small and is not retried, so call it again if you want a hardened seed.
Ownership
Section titled “Ownership”An Rng is one heap allocation. rng_new returns a pointer the caller owns; release it with free like any other heap value. See Memory for how alloc and free behave.
A checked example
Section titled “A checked example”A fixed seed makes the sequence deterministic, so two generators seeded the same way draw the same words in the same order. The sample below leans on that to check itself without pinning any particular draw.
@paradigm procedural
@import std.rand
func main() -> int32 { // A fixed seed makes the sequence deterministic: two generators seeded the // same way draw the same words, in the same order. a: *Rng = rng_new(42) b: *Rng = rng_new(42) if rng_next(a) == rng_next(b) { println("deterministic") // deterministic }
// rng_range narrows a draw to [lo, hi). A d6 roll lives in [1, 7). roll: int64 = rng_range(a, 1, 7) if roll >= 1 && roll < 7 { println("rolled in range") // rolled in range }
// rng_float narrows to a [0, 1) float64. f: float64 = rng_float(a) if f >= 0.0 && f < 1.0 { println("float in range") // float in range }
// shuffle runs Fisher-Yates in place over an int64[]. The slice binding // needs no mut; the swaps write the buffer the slice views. deck: int64[] = [1, 2, 3, 4, 5] shuffle(a, deck) println("shuffled {} cards", deck.len) // shuffled 5 cards
free(a) free(b) return 0}See also
Section titled “See also”- std.math: the libm scalar functions, the other numeric utility added in 1.4.0.
- Memory: the
allocandfreerules behind the heapRng. - stdlib overview: the full module list and how imports resolve.