Gerador de Números Aleatórios: amostragem com e sem reposição
Sortear números dentro de um intervalo parece trivial, mas esconde uma distinção estatística que muda completamente o algoritmo por trás: amostragem com reposição (o mesmo número pode sair mais de uma vez) versus sem reposição (cada número só pode sair uma vez, como em um sorteio de loteria). São dois problemas diferentes, com implementações diferentes neste gerador.
Com repetição: amostragem independente
Quando repetição é permitida, cada número é sorteado de forma
totalmente independente dos anteriores — uma chamada de
random_int(min, max) por número desejado. Estatisticamente,
isso é uma amostragem com reposição: a probabilidade de qualquer valor
dentro do intervalo é a mesma a cada sorteio, e o mesmo número pode
aparecer várias vezes no resultado final, exatamente como no lançamento
repetido de um dado.
Sem repetição: por que não é só "descartar duplicatas"
A abordagem ingênua de sortear repetidamente e descartar valores já
sorteados fica progressivamente mais lenta (e no limite, trava) quando
a quantidade pedida se aproxima do tamanho do intervalo — se o
intervalo tem 100 números e 99 já foram sorteados, a chance de acertar
o único número restante por tentativa aleatória é de 1%. Este gerador
evita esse problema construindo a lista completa do intervalo
(range(min, max)), embaralhando-a inteira com Fisher-Yates
(shuffle()) e pegando os primeiros N elementos — um
algoritmo de complexidade linear, independente de quão próximo N está
do tamanho do intervalo, sem risco de loop demorado.
Uso em testes de sorteio, amostragem e distribuição de carga
Sistemas de sorteio (rifas, brindes, distribuição de testes A/B), algoritmos de amostragem estatística, e testes de distribuição de carga (escolher aleatoriamente qual servidor/worker recebe uma tarefa) todos dependem dessa mesma primitiva. Testar a lógica de sorteio de um sistema real com uma fonte de números controlável — em vez de depender do gerador de números aleatórios embutido na linguagem de produção diretamente no teste — permite verificar casos de borda (intervalo com um único valor possível, quantidade solicitada igual ao tamanho do intervalo) de forma determinística e reproduzível.