Random Numbers
const std = @import("std");
const expect = std.testing.expect;
test "a seeded generator is reproducible" {
var prng = std.Random.DefaultPrng.init(42);
const random = prng.random();
const first = random.int(u32);
// Same seed, same sequence: that is what makes tests deterministic.
var again = std.Random.DefaultPrng.init(42);
try expect(again.random().int(u32) == first);
}
test "ranges" {
var prng = std.Random.DefaultPrng.init(0);
const random = prng.random();
for (0..100) |_| {
const die = random.intRangeAtMost(u8, 1, 6); // inclusive
try expect(die >= 1 and die <= 6);
const index = random.uintLessThan(usize, 10); // exclusive
try expect(index < 10);
}
}
test "floats and booleans" {
var prng = std.Random.DefaultPrng.init(7);
const random = prng.random();
const f = random.float(f64); // [0, 1)
try expect(f >= 0.0 and f < 1.0);
_ = random.boolean();
}
test "shuffle a slice" {
var prng = std.Random.DefaultPrng.init(1);
var items = [_]u8{ 1, 2, 3, 4, 5 };
prng.random().shuffle(u8, &items);
var sum: u32 = 0;
for (items) |i| sum += i;
try expect(sum == 15); // same elements, different order
}There is no global rand(). You create a generator, seed it, and pass its
Random interface where it is needed: the same explicitness Zig applies to
allocators and I/O.
var prng = std.Random.DefaultPrng.init(seed);
const random = prng.random();
Seeding
A fixed seed gives a reproducible sequence, which is what you want in tests. For real unpredictability seed from the OS:
var prng = std.Random.DefaultPrng.init(seed_from_os);
std.crypto.random is the cryptographically secure source, and is the one to
use for tokens, keys, or anything an attacker should not predict.
DefaultPrng is fast, not secure. Do not use it for secrets.
Ranges
| Call | Range |
|---|---|
intRangeAtMost(T, lo, hi) | lo..=hi inclusive |
intRangeLessThan(T, lo, hi) | lo..hi |
uintLessThan(T, hi) | 0..hi |
float(T) | [0, 1) |
These handle modulo bias properly. random.int(u8) % 6 does not, and skews
toward low values.
shuffle permutes a slice in place.