Perl 28/13 ~ 2,15
sub r{$s^=~($s^=$s/7215)<<8}
arquivo de log aqui
Perl 29/13 ~ 2.23
sub r{$s^=~($s^=$s<<8)/60757}
arquivo de log aqui
Isso é uma variação de um Xorshift , usando a divisão de ponto flutuante em vez de um deslocamento à direita. Ambos foram aprovados em 13 de 15 testes, sendo reprovados apenas nos testes 6 e 7.
Não sei exatamente quanto tempo dura o ciclo, mas como o código a seguir não termina em um curto período de tempo, é provável que o 2 32 esteja completo :
$start = r();
$i++ while $start != r();
print $i;
Perl 39/10 = 3,9
$s=$^T;sub r{~($s=$s*$s%4294969373)||r}
Nota: se você estiver procurando por um PRNG de estilo Blum-Blum-Shub, a solução de Keith Randall é muito melhor do que qualquer um deles.
Como na minha solução original abaixo, esta também é uma implementação do Blum Blum Shub, com uma grande diferença. Eu uso um módulo um pouco maior que 2 32 ( M = 50971 • 84263 ) e, sempre que um valor é encontrado, ele não é um número inteiro válido de 32 bits (ou seja, maior que 2 32 ), ele retorna o próximo valor no rotação em vez disso. Em essência, esses valores são eliminados, deixando o restante da rotação imperturbável, resultando em uma distribuição quase uniforme.
Parece ter ajudado. Além de passar nos mesmos 9 testes de antes, agora também passa no teste de Distância Mínima de forma convincente. Um arquivo de log de amostra pode ser encontrado aqui .
Perl 33/9 ~ 3,67 (Inválido?)
$s=$^T;sub r{$s=$s*$s%4294951589}
Nota: esta solução pode ser considerada inválida, pois os 0,00037% mais altos do intervalo nunca serão observados.
Uma implementação rápida e suja do Blum Blum Shub . Eu reivindico os seguintes resultados:
1. passed - Birthday Spacings
2. FAILED - Overlapping Permutations
3. passed - Ranks of 31x31 and 32x32 Matrices
4. passed - Ranks of 6x8 Matrices
5. FAILED - Monkey Tests on 20-bit Words
6. FAILED - Monkey Tests OPSO, OQSO, DNA
7. FAILED - Count the 1s in a Stream of Bytes
8. passed - Count the 1s for Specific Bytes
9. passed - Parking Lot Test
10. FAILED - Minimum Distance Test
11. passed - Random Spheres Test
12. FAILED - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test
Um arquivo de log de amostra pode ser encontrado aqui , fique à vontade para contestar qualquer um dos resultados. O arquivo para diehard pode ser gerado da seguinte maneira:
print pack('N', r()) for 1..4194304
e, em seguida, canalize a saída em um arquivo. Parece que a Distância mínima pode ter passado, mas se você executá-la várias vezes, é sempre muito próxima de 1,0 , o que indica falha.
Detalhes
Em geral, o Blum Blum Shub é um péssimo PRNG, mas seu desempenho pode ser melhorado com a escolha de um bom módulo. O M que escolhi é 7027 • 611207 . Ambos os fatores primos, p e q , têm resíduo modular 3 (mod 4) e gcd (φ (p-1), φ (q-1)) = 2 , que é o mais baixo possível.
Embora esses sejam os únicos critérios listados na página da wiki, isso não parece suficiente. Quase todo o módulo que tentei falhou em todos os testes. Mas há alguns que passarão em alguns dos testes, e o que eu escolhi parece ser excepcionalmente bom, por qualquer motivo.
Como observação final, o Teste 5, por si só, parece ser um bom indicador de quão bom é o PRNG. Se ele quase não passar no Teste 5, falhará espetacularmente com o restante.
BÔNUS: Perl 62/14 ≈ 4.43
$t=$^T;sub r{$t|=(($s=$s/2|$t%2<<31)^($t/=2))<<31for 1..37;$t}
Apenas para geeks, esta é uma versão de 32 bits do PRNG usada no Tetris for NES original. Surpreendentemente, ele passa em 14 dos 15 testes!
1. passed - Birthday Spacings
2. passed - Overlapping Permutations
3. passed - Ranks of 31x31 and 32x32 Matrices
4. passed - Ranks for 6x8 Matrices
5. passed - Monkey Tests on 20-bit Words
6. passed - Monkey Tests OPSO, OQSO, DNA
7. FAILED - Count the 1s in a Stream of Bytes
8. passed - Count the 1s for Specific Bytes
9. passed - Parking Lot Test
10. passed - Minimum Distance Test
11. passed - Random Spheres Test
12. passed - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test
Arquivo de log de amostra pode antes aqui .
É certo que o 1..37
bit não é uma transcrição exata. Na versão original, a rotina de entropia é atualizada 60 vezes por segundo e depois consultada em intervalos aleatórios, em grande parte dependente da entrada do usuário. Para quem quer desmontar a ROM, a rotina de entropia começa em 0xAB47
.
Pseudo-código no estilo Python:
carry = entropy_1 & 1
entropy_1 >>= 1
entropy_2 = (entropy_2 >> 1) | (carry << 31)
carry = (entropy_1 & 1) ^ (entropy_2 & 1)
entropy_1 |= carry << 31