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
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento básico de Zig. Consulte a introdução ao Zig
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
Use
getrandompara seed em produção: Garante entropia do sistema operacional.Seed fixa para testes: Permite reproduzir sequências para depuração.
DefaultPrngé rápido mas não criptográfico: Para criptografia, use fontes de entropia do OS diretamente.intRangeAtMostinclui os limites:intRangeAtMost(u8, 1, 6)retorna valores de 1 a 6, inclusive.Shuffle é in-place:
rand.shufflemodifica o array original.
Receitas Relacionadas
- Operações Matemáticas - Funções matemáticas
- Hashing SHA256/MD5 - Funções de hash
- Benchmark e Performance - Medir performance
- Testes Unitários Básicos - Testar com seed fixa