Como Gerar Números Aleatórios em Zig

Introdução

Gerar números aleatórios é essencial para jogos, simulações, testes, criptografia e muitas outras aplicações. Zig oferece geradores de números aleatórios na biblioteca padrão através de std.Random, com suporte a diferentes algoritmos e fontes de entropia.

Nesta receita, você aprenderá a gerar números aleatórios de diferentes tipos e distribuições.

Pré-requisitos

Gerar Números Inteiros Aleatórios

const std = @import("std");

pub fn main() !void {
    // Usar DefaultPrng com seed do sistema
    var prng = std.Random.DefaultPrng.init(blk: {
        var seed: u64 = undefined;
        std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
        break :blk seed;
    });
    const rand = prng.random();

    // Gerar inteiros de diferentes tipos
    std.debug.print("u8:  {d}\n", .{rand.int(u8)});
    std.debug.print("u16: {d}\n", .{rand.int(u16)});
    std.debug.print("u32: {d}\n", .{rand.int(u32)});
    std.debug.print("i32: {d}\n", .{rand.int(i32)});

    // Gerar em um intervalo [0, limite)
    std.debug.print("\nDado (1-6): {d}\n", .{rand.intRangeAtMost(u8, 1, 6)});
    std.debug.print("Porcentagem (0-100): {d}\n", .{rand.intRangeAtMost(u8, 0, 100)});

    // Gerar 10 números entre 1 e 100
    std.debug.print("\n10 números entre 1 e 100:\n", .{});
    for (0..10) |_| {
        std.debug.print("  {d}\n", .{rand.intRangeAtMost(u32, 1, 100)});
    }
}

Gerar Números de Ponto Flutuante

const std = @import("std");

pub fn main() !void {
    var prng = std.Random.DefaultPrng.init(blk: {
        var seed: u64 = undefined;
        std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
        break :blk seed;
    });
    const rand = prng.random();

    // Float entre 0.0 e 1.0
    std.debug.print("Floats [0, 1):\n", .{});
    for (0..5) |_| {
        std.debug.print("  {d:.6}\n", .{rand.float(f64)});
    }

    // Float em intervalo customizado [min, max)
    const min: f64 = 20.0;
    const max: f64 = 30.0;
    std.debug.print("\nTemperaturas [{d:.0}, {d:.0}):\n", .{ min, max });
    for (0..5) |_| {
        const temp = min + rand.float(f64) * (max - min);
        std.debug.print("  {d:.1}°C\n", .{temp});
    }
}

Embaralhar um Array (Shuffle)

const std = @import("std");

pub fn main() !void {
    var prng = std.Random.DefaultPrng.init(blk: {
        var seed: u64 = undefined;
        std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
        break :blk seed;
    });
    const rand = prng.random();

    // Embaralhar cartas
    var cartas = [_][]const u8{
        "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
    };

    std.debug.print("Original: ", .{});
    for (cartas) |c| std.debug.print("{s} ", .{c});

    rand.shuffle([]const u8, &cartas);

    std.debug.print("\nEmbaralhado: ", .{});
    for (cartas) |c| std.debug.print("{s} ", .{c});
    std.debug.print("\n", .{});

    // Embaralhar números
    var numeros = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    rand.shuffle(i32, &numeros);

    std.debug.print("\nNúmeros embaralhados: ", .{});
    for (numeros) |n| std.debug.print("{d} ", .{n});
    std.debug.print("\n", .{});
}

Seed Determinística para Testes

const std = @import("std");

pub fn main() !void {
    // Seed fixa: sempre gera a mesma sequência
    var prng = std.Random.DefaultPrng.init(42);
    const rand = prng.random();

    std.debug.print("Sequência determinística (seed=42):\n", .{});
    for (0..5) |_| {
        std.debug.print("  {d}\n", .{rand.intRangeAtMost(u32, 1, 100)});
    }

    // Executar novamente com a mesma seed gera os mesmos números
    var prng2 = std.Random.DefaultPrng.init(42);
    const rand2 = prng2.random();

    std.debug.print("\nMesma sequência novamente:\n", .{});
    for (0..5) |_| {
        std.debug.print("  {d}\n", .{rand2.intRangeAtMost(u32, 1, 100)});
    }
}

Preencher Buffer com Bytes Aleatórios

const std = @import("std");

pub fn main() !void {
    var prng = std.Random.DefaultPrng.init(blk: {
        var seed: u64 = undefined;
        std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
        break :blk seed;
    });
    const rand = prng.random();

    // Preencher buffer com bytes aleatórios
    var buffer: [32]u8 = undefined;
    rand.bytes(&buffer);

    std.debug.print("Bytes aleatórios: ", .{});
    for (buffer) |b| {
        std.debug.print("{X:0>2}", .{b});
    }
    std.debug.print("\n", .{});

    // Booleano aleatório
    std.debug.print("\nCara ou coroa: ", .{});
    for (0..10) |_| {
        const cara = rand.boolean();
        std.debug.print("{s} ", .{if (cara) "C" else "K"});
    }
    std.debug.print("\n", .{});
}

Exemplo Prático: Simulação de Dados

const std = @import("std");

pub fn main() !void {
    var prng = std.Random.DefaultPrng.init(blk: {
        var seed: u64 = undefined;
        std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
        break :blk seed;
    });
    const rand = prng.random();

    const num_lancamentos: u32 = 10000;
    var contagem = [_]u32{0} ** 6;

    // Simular lançamentos
    for (0..num_lancamentos) |_| {
        const dado = rand.intRangeAtMost(u8, 1, 6);
        contagem[dado - 1] += 1;
    }

    // Mostrar distribuição
    std.debug.print("Distribuição de {d} lançamentos:\n", .{num_lancamentos});
    for (contagem, 1..) |c, face| {
        const pct: f64 = @as(f64, @floatFromInt(c)) / @as(f64, @floatFromInt(num_lancamentos)) * 100.0;
        std.debug.print("  Face {d}: {d:>5} ({d:.1}%)\n", .{ face, c, pct });
    }
}

Dicas e Boas Práticas

  1. Use getrandom para seed em produção: Garante entropia do sistema operacional.

  2. Seed fixa para testes: Permite reproduzir sequências para depuração.

  3. DefaultPrng é rápido mas não criptográfico: Para criptografia, use fontes de entropia do OS diretamente.

  4. intRangeAtMost inclui os limites: intRangeAtMost(u8, 1, 6) retorna valores de 1 a 6, inclusive.

  5. Shuffle é in-place: rand.shuffle modifica o array original.

Receitas Relacionadas

Tutoriais Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.