⚡ Zig Guide LiveUnofficial
✓ Zig 0.17.0-dev.1454+5faa79730On an older Zig?

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

CallRange
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.