Random
Números pseudo-aleatórios baseados em xorshift64\* — rápidos, com período completo de 64 bits. Não é criptograficamente seguro, mas é exatamente o que você quer para embaralhar, amostrar, testes aleatorizados e simulações reproduzíveis.
Use seed determinística com `Rng::with_seed` para execuções que possam ser repetidas, ou a partir do relógio monotônico com `Rng::from_clock` para "aleatório o suficiente".
Import
import stdlib::random::*;
Visão geral da interface pública
O módulo expõe exatamente um tipo e oito métodos — três construtores/destrutor e cinco auxiliares de sorteio. Tudo abaixo é construído sobre next_i64.
| Item | Assinatura | Finalidade |
|---|---|---|
Rng |
pub struct Rng { state: i64 } |
O gerador (um único i64 de estado). |
with_seed |
pub fn with_seed(seed: i64) -> *Rng |
Constrói a partir de uma seed conhecida (reproduzível). |
from_clock |
pub fn from_clock() -> *Rng |
Constrói a partir de now_ns() ("aleatório o suficiente"). |
free |
pub fn free(self: *Rng) |
Libera o gerador. |
next_i64 |
pub fn next_i64(self: *Rng) -> i64 |
Valor bruto de 64 bits (pode transbordar; pode ser negativo). |
next_int |
pub fn next_int(self: *Rng) -> i32 |
i32 não-negativo em [0, 2^31 - 1]. |
range |
pub fn range(self: *Rng, lo: i32, hi: i32) -> i32 |
i32 uniforme em [lo, hi). |
next_f64 |
pub fn next_f64(self: *Rng) -> f64 |
f64 uniforme em [0.0, 1.0). |
next_bool |
pub fn next_bool(self: *Rng) -> bool |
true com probabilidade ~0,5. |
O gerador Rng
pub struct Rng { state: i64 }
Rng guarda um único i64 de estado interno. É alocado na heap pelos seus construtores e deve ser liberado com `free` — use defer para garantir uso sem vazamentos.
Construção
| Função | Assinatura | Descrição |
|---|---|---|
with_seed |
pub fn with_seed(seed: i64) -> *Rng |
Cria um Rng a partir de uma seed conhecida; a mesma seed sempre produz o mesmo fluxo. |
from_clock |
pub fn from_clock() -> *Rng |
Cria um Rng com seed derivada do relógio monotônico (now_ns()). |
free |
pub fn free(self: *Rng) |
Libera o gerador. |
Rng::with_seed
pub fn with_seed(seed: i64) -> *Rng
Constrói um Rng com um estado inicial conhecido. A mesma seed sempre produz o mesmo fluxo, tornando esta a escolha certa para testes e simulações reproduzíveis.
import stdlib::random::*;
fn main() -> i32 {
let r: *Rng = Rng::with_seed(42);
defer r.free();
println!("first draw", r.next_int()); // mesmo valor em toda execução
return 0;
}
Rng::from_clock
pub fn from_clock() -> *Rng
Constrói um Rng com seed derivada do relógio monotônico. Internamente é apenas Rng::with_seed(now_ns()).
import stdlib::random::*;
fn main() -> i32 {
let r: *Rng = Rng::from_clock();
defer r.free();
for i in 0..5 { println!("d6", r.range(1, 7)); } // cinco lançamentos de dado
return 0;
}
free
pub fn free(self: *Rng)
Libera a alocação na heap do gerador. Como os construtores retornam um *Rng bruto, você é responsável pelo tempo de vida — defer r.free(); logo após a construção é o padrão idiomático.
Sorteando valores
Cada sorteio avança o estado interno no lugar. O catálogo completo:
| Método | Assinatura | Intervalo / resultado |
|---|---|---|
next_i64 |
pub fn next_i64(self: *Rng) -> i64 |
Valor bruto de 64 bits (pode transbordar); entropia total. |
next_int |
pub fn next_int(self: *Rng) -> i32 |
i32 não-negativo em [0, 2^31 - 1]. |
range |
pub fn range(self: *Rng, lo: i32, hi: i32) -> i32 |
i32 uniforme em [lo, hi). |
next_f64 |
pub fn next_f64(self: *Rng) -> f64 |
f64 uniforme em [0.0, 1.0). |
next_bool |
pub fn next_bool(self: *Rng) -> bool |
true com probabilidade ~0,5. |
Os cinco juntos, a partir de um gerador com seed fixa:
import stdlib::random::*;
fn main() -> i32 {
let r: *Rng = Rng::with_seed(42);
defer r.free();
let raw: i64 = r.next_i64(); // 64 bits completos, pode ser negativo
let n: i32 = r.next_int(); // 0 .. 2^31-1
let d6: i32 = r.range(1, 7); // 1..=6
let p: f64 = r.next_f64(); // [0.0, 1.0)
let flip: bool = r.next_bool(); // ~50/50
println!("raw", raw);
println!("int", n);
println!("d6", d6);
if flip { println!("heads"); } else { println!("tails"); }
if p < 0.5 { println!("low half"); }
return 0;
}
next_i64
pub fn next_i64(self: *Rng) -> i64
Próximo valor bruto de 64 bits: um passo de xorshift seguido de uma multiplicação por uma constante ímpar. O resultado pode transbordar e pode ser negativo. Use este método quando quiser todos os 64 bits de entropia (hashing, jitter); para inteiros delimitados, prefira `range`. Todos os outros auxiliares de sorteio são invólucros finos sobre este.
let raw: i64 = r.next_i64();
next_int
pub fn next_int(self: *Rng) -> i32
Próximo i32 não-negativo. O valor é mascarado para 31 bits, de forma que o resultado seja sempre positivo após o cast i64 -> i32 — manter todos os 32 bits faria o bit mais significativo torná-lo negativo. Intervalo: [0, 2^31 - 1].
let n: i32 = r.next_int(); // 0 .. 2^31-1
range
pub fn range(self: *Rng, lo: i32, hi: i32) -> i32
Inteiro uniforme no intervalo semiaberto [lo, hi). Retorna lo quando o intervalo é vazio (hi <= lo), portanto nunca falha com um intervalo degenerado.
let dice: i32 = r.range(1, 7); // d6 -> 1..=6
let pct: i32 = r.range(0, 100); // 0..=99
let same: i32 = r.range(5, 5); // intervalo vazio -> retorna 5
next_f64
pub fn next_f64(self: *Rng) -> f64
Float uniforme em [0.0, 1.0). Construído a partir dos 53 bits superiores de um sorteio bruto, de modo que o resultado caiba exatamente na mantissa de um f64 sem erro de arredondamento nas bordas. Ideal para limiares de probabilidade e ensaios de Bernoulli.
let p: f64 = r.next_f64();
if p < 0.1 { /* executa ~10% das vezes */ }
next_bool
pub fn next_bool(self: *Rng) -> bool
Cara ou coroa — retorna true com probabilidade ~0,5 (testa o bit menos significativo de um sorteio bruto).
if r.next_bool() { println!("heads"); } else { println!("tails"); }
Reprodutibilidade
Dois geradores construídos a partir da mesma seed produzem sequências idênticas, o que torna as execuções com seed fixa reproduzíveis — registre a seed e você poderá repetir a execução exata mais tarde.
import stdlib::random::*;
fn main() -> i32 {
let a: *Rng = Rng::with_seed(12345);
defer a.free();
let b: *Rng = Rng::with_seed(12345);
defer b.free();
let mut matched: bool = true;
for i in 0..10 {
if a.next_i64() != b.next_i64() { matched = false; }
}
if matched { println!("identical streams"); }
return 0;
}
Verificação de sanidade da distribuição — um ensaio de Bernoulli construído sobre next_f64:
import stdlib::random::*;
fn main() -> i32 {
// Conta ~250 acertos em 1000 tentativas com p = 0.25.
let r: *Rng = Rng::with_seed(0); // 0 é reescrito para um estado não-nulo
defer r.free();
let mut hits: i32 = 0;
for i in 0..1000 {
if r.next_f64() < 0.25 { hits = hits + 1; }
}
println!("approx 250", hits);
return 0;
}
Receitas
Este módulo fornece apenas a seed e os cinco auxiliares de sorteio; as operações comuns sobre coleções são fáceis de implementar você mesmo.
Selecionando um elemento aleatório (choice)
Indexe um vetor com range(0, len):
import stdlib::random::*;
fn pick(r: *Rng, v: *Vector<i32>) -> i32 {
let i: i32 = r.range(0, v.len() as i32);
return v.get(i as usize);
}
fn main() -> i32 {
let nums: *Vector<i32> = Vector::new();
defer nums.free();
push_all!(nums, 10, 20, 30, 40, 50);
let r: *Rng = Rng::with_seed(99);
defer r.free();
for i in 0..3 { println!("pick", pick(r, nums)); }
return 0;
}
Embaralhando (Fisher–Yates)
Percorra do último índice para baixo, trocando cada elemento com um anterior (ou igual) escolhido aleatoriamente. Note o limite superior inclusivo r.range(0, i + 1).
import stdlib::random::*;
fn shuffle(r: *Rng, v: *Vector<i32>) {
let n: i32 = v.len() as i32;
let mut i: i32 = n - 1;
while i > 0 {
let j: i32 = r.range(0, i + 1); // 0..=i
let tmp: i32 = v.get(i as usize);
v.set(i as usize, v.get(j as usize));
v.set(j as usize, tmp);
i = i - 1;
}
}
fn main() -> i32 {
let deck: *Vector<i32> = Vector::new();
defer deck.free();
for k in 0..8 { deck.push(k); }
let r: *Rng = Rng::with_seed(2024);
defer r.free();
shuffle(r, deck);
for k in 0..deck.len() { println!("card", deck.get(k)); }
return 0;
}
Bytes aleatórios
Não há auxiliar bytes; sorteie cada byte com range(0, 256):
import stdlib::random::*;
fn fill_bytes(r: *Rng, out: *Vector<i32>, count: i32) {
let mut i: i32 = 0;
while i < count {
out.push(r.range(0, 256)); // um byte 0..=255
i = i + 1;
}
}
fn main() -> i32 {
let buf: *Vector<i32> = Vector::new();
defer buf.free();
let r: *Rng = Rng::with_seed(7);
defer r.free();
fill_bytes(r, buf, 16);
println!("len", buf.len());
println!("first", buf.get(0));
return 0;
}
Veja também
- `time` —
now_ns()é a função da qualfrom_clockextrai a seed. - A referência de
vector—Vector::new,push,get,set,lenusados nas receitas acima.