Artigo original: Random Number Generator: How Do Computers Generate Random Numbers?

As pessoas usam números aleatórios há milênios. Portanto, o conceito não é novo. Desde a loteria na antiga Babilônia, passando pelas mesas de roleta em Monte Carlo até os jogos de dados em Las Vegas, o objetivo é deixar o resultado final nas mãos de uma chance aleatória.

Jogos de azar à parte, a aleatoriedade tem muitos usos na ciência, estatística, criptografia e muito mais. No entanto, o uso de dados, moedas ou meios similares como um dispositivo para produzir a aleatoriedade tem suas limitações.

Por causa da natureza mecânica destas técnicas, gerar grandes quantidades de números aleatórios requer muito tempo e trabalho. Graças à engenhosidade humana, temos ferramentas e métodos mais poderosos à nossa disposição.

Métodos para a geração de números aleatórios

Números verdadeiramente aleatórios

image-145-opt
Imagem do dispositivo de processamento analógico de entrada e saída digital. Foto por Harrison Broadbent

Vamos considerar dois métodos principais usados para gerar números aleatórios. O primeiro método é baseado em um processo físico e colhe a fonte da aleatoriedade de algum fenômeno físico que se espera que seja aleatório.

Tal fenômeno se dá fora do computador. Ele é medido e ajustado para possíveis enviesamentos devido ao processo de medição. Exemplos incluem a decadência radioativa, o efeito fotoelétrico, a radiação cósmica de fundo, o ruído atmosférico (que usaremos neste artigo) e muitos outros.

Assim, os números aleatórios gerados com base nessa aleatoriedade são considerados números aleatórios "verdadeiros".

Tecnicamente, a parte de hardware consiste em um dispositivo que converte energia de uma forma para outra (por exemplo, radiação para um sinal elétrico), um amplificador e um conversor analógico-digital para transformar a saída em um número digital.

O que são números pseudoaleatórios?

image-146-opt
Imagem do código de computador fluindo através da tela do computador. Foto por Markus Spiske.

Como alternativa aos números aleatórios "verdadeiros", o segundo método de geração de números aleatórios envolve algoritmos computacionais que podem produzir resultados aparentemente aleatórios.

Por que aparentemente aleatórios? Porque os resultados finais obtidos são, de fato, completamente determinados por um valor inicial também conhecido como o valor de seed ou key. Portanto, se você souber o valor de chave (key) e como o algoritmo funciona, poderá reproduzir esses resultados aparentemente aleatórios.

Geradores de números aleatórios deste tipo são frequentemente chamados de geradores de números pseudoaleatórios e, como resultado, a saída deles são os números pseudoaleatórios.

Mesmo que este tipo de gerador, normalmente, não reúna nenhum dado de fontes de aleatoriedade natural, essa coleta de chaves pode ser possível quando necessário.

Vamos comparar alguns aspectos dos verdadeiros geradores de números aleatórios (ou TRNGs) e dos geradores de números pseudoaleatórios (ou PRNGs).

Os PRNGs são mais rápidos do que os TRNGs. Devido à sua natureza determinista, eles são úteis quando você precisa repetir uma sequência de eventos aleatórios. Isto ajuda muito nos testes de código, por exemplo.

Por outro lado, os TRNGs não são periódicos e funcionam melhor em funções sensíveis de segurança, como a criptografia.

Um período é o número de iterações que um PRNG passa antes de começar a se repetir. Assim, sendo todas as outras coisas iguais, um PRNG com um período mais longo levaria mais recursos computacionais para ser previsto e decifrado.

Exemplo de algoritmo para o gerador de números pseudoaleatórios

Um computador executa um código que é baseado em um conjunto de regras a serem seguidas. Para PRNGs em geral, essas regras giram em torno do seguinte:

  1. Aceitar algum número de entrada inicial, ou seja, uma seed ou key.
  2. Aplicar essa seed em uma sequência de operações matemáticas para gerar o resultado. Esse resultado é o número aleatório.
  3. Usar esse número aleatório resultante como seed para a próxima iteração.
  4. Repetir o processo para emular a aleatoriedade.

Vejamos um exemplo.

O gerador linear congruencial

Esse gerador produz uma série de números pseudoaleatórios. Dada uma seed inicial X0 e parâmetros inteiros a como multiplicador, b como incremento, e m como módulo, o gerador é definido pela relação linear: Xn ≡ (aXn-1 + b)mod m. Ou, usando uma sintaxe mais amigável da programação: Xn = (a * Xn-1 + b) % m.

Cada um desses membros tem que satisfazer as seguintes condições:

  • m > 0 (o módulo é positivo),
  • 0 < a < m (o multiplicador é positivo, mas menor do que o módulo),
  • 0 b < m (o incremento não é negativo, mas menor do que o módulo), e
  • 0 X0 < m (a seed não é negativa, mas é menor que o módulo).

Vamos criar uma função em JavaScript que tome os valores iniciais como argumentos e retorne um array de números aleatórios de um determinado comprimento:

    // x0=seed; a=miltiplicador; b=incremento; m=módulo; n=tamanho do array desejado; 
	const linearRandomGenerator = (x0, a, b, m, n) => {
        const results = []
        for (let i = 0; i < n; i++) {
        	x0 = (a * x0 + b) % m
            results.push(x0)
        }
        return results
    }
	

O gerador linear congruencial é um dos mais antigos e mais conhecidos algoritmos PRNG.

Quanto aos algoritmos geradores de números aleatórios que são executáveis por computadores, eles datam dos anos 40 e 50 (o método do quadrado do meio e o gerador de Lehmer, por exemplo – textos explicativos em inglês) e continuam a ser escritos hoje (Xoroshiro128+, Squares RNG e mais – textos explicativos em inglês).

Um gerador de números aleatórios de amostra

Quando decidi escrever este artigo sobre a incorporação de um gerador de números aleatórios em uma página da web, tive que fazer uma escolha.

Eu poderia ter usado a função Math.random() do JavaScript como base e gerar a saída em números pseudoaleatórios como já fiz em artigos anteriores (veja Multiplication Chart - Code Your Own Times Table – texto em inglês).

Este artigo, no entanto, é sobre a geração de números aleatórios. Portanto, decidi aprender a reunir dados "verdadeiros" baseados na aleatoriedade e compartilhar a minha descoberta com vocês.

Assim, abaixo vemos um gerador de números aleatórios "verdadeiros". Defina os parâmetros e pressione Generate (em português, Gerar).

True Random Number Generator
Result:

O código busca dados de uma das APIs, cortesia da Random.org. Este recurso on-line tem uma infinidade de ferramentas úteis e customizáveis e vem com excelente documentação para acompanhá-lo.

A aleatoriedade vem do ruído atmosférico. Consegui usar funções assíncronas. Isso é um enorme benefício para o futuro. A função principal se parece com isto:

    // Gera um número aleatório dentro do intervalo indicado pelo usuário
   	const getRandom = async (min, max, base) => {
   		const response = await 	fetch("https://www.random.org/integers/?num=1&min="+min+"
    &max="+max+"&col=1&base="+base+"&format=plain&rnd=new")
          	return response.text() 
   	} 

Os parâmetros necessários permitem que um usuário personalize a saída de números aleatórios. Por exemplo, min e max permitem definir limites inferiores e superiores na saída gerada. A base determina se a saída é impressa como binária, decimal ou hexadecimal.

Novamente, escolhi esta configuração, mas há muitas mais disponíveis na fonte.

Ao clicar no botão Generate, a função handleGenerate() é chamada. Ela, por sua vez, invoca a função assíncrona getRandom(), gerencia o tratamento de erros e os resultados das saídas:

    // Tratamento do resultado
    const handleGenerate = () => {
    	handleActive(generateButton)
        const base = binary.checked ? 2 : decimal.checked ? 10 : 16
        if (!minimum.value || !maximum.value) {
            prompter.style.color = 'red' 
        	prompter.textContent = "Enter Min & Max values"
        } else {
        	getRandom(minimum.value, maximum.value, base).then((data) => {
        		resultValue.textContent = data
        		prompter.textContent = ""    
        	}).catch((error) => {
        		resultValue.textContent = 'ERROR'
        		prompter.textContent = 'Connection error. Unable to 						generate';    
        	})
       		 handleRestart()
        }
        
   }

O restante do código trata da estrutura do HTML, da aparência e do estilo.

O código está pronto para ser incorporado e utilizado dentro da página da web. Eu o separei em partes componentes e o forneci com comentários detalhados. Ele pode ser facilmente modificado. Você também pode modificar a funcionalidade e os estilos conforme suas necessidades.

Abaixo temos o link para o repositório no GitHub com o código completo: https://github.com/sandroarobeli/random-generator