Embora existam muitas perguntas sobre código de golfe envolvendo aleatoriedade, ainda não vi uma que realmente solicite a construção de um gerador de números pseudoaleatórios algorítmicos. Existe um que pede para você gerar um fluxo de bits, mas os testes de aleatoriedade fornecidos nesse não foram muito rigorosos e não são códigos de golfe.
O programa que você escreve terá uma única função que pode ser chamada que retornará um número inteiro aleatório de 0 a 4294967295. Essa função não deve chamar bibliotecas ou outras funções que também não foram gravadas como parte do programa, especialmente chamadas para / dev / random ou a biblioteca rand () interna de um idioma. Mais especificamente, você está limitado aos operadores básicos do idioma em que está trabalhando, como aritmética, acesso à matriz e instruções de controle de fluxo condicional.
A pontuação do seu programa é calculada da seguinte forma:
Score = C / R
Onde C é o comprimento do código em caracteres e R é o número de testes de Diehard que o seu gerador passa (se o gerador de números aleatórios não passar em pelo menos um teste de Diehard, sua pontuação é infinita e é desqualificada). Seu gerador passa no teste Diehard se o arquivo gerado fornecer uma faixa de valores P que parecem distribuídos uniformemente ao longo do intervalo [0, 1).
Para calcular R, use seu gerador de números aleatórios com sua semente padrão para gerar um arquivo de dados binários de 16 MB. Cada chamada da função retorna quatro bytes; se sua função for muito lenta para retornar bytes, isso fará com que uma troca atinja uma pontuação baixa pela dificuldade em testar. Em seguida, execute-o através dos testes Diehard e verifique os valores-P fornecidos. (Não tente implementá-las você mesmo; use as fornecidas aqui )
Menor pontuação ganha, é claro.
fonte
Respostas:
Mathematica, 32/15 = 2,133
Uma implementação direta do BBS .
Arquivo binário gerado com:
Resumo dos Resultados:
Cheio
random.bin
aqui.Arquivo de log completo aqui.
fonte
28!-67
é um tanto proibitivo. Existe um valor menor que caberia em um número inteiro de 64 bits?Perl 28/13 ~ 2,15
arquivo de log aqui
Perl 29/13 ~ 2.23
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 :
Perl 39/10 = 3,9
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?)
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:
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:
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
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!
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 em0xAB47
.Pseudo-código no estilo Python:
fonte
Python, 46/15 = 3.0666
Usa exponenciação modular para gerar aleatoriedade. 2 ** 32-5 é o maior primo menor que 2 ^ 32. (O mesmo acordo com a impossibilidade de executar o teste nº 2).
fonte
\r
e\n
para\r\n
, o que obviamente distorce os resultados. Uma correção é escrever o arquivo diretamente usandof = open('file.bin', 'wb')
ef.write
.Ruby, 32/15 = 2,1333
Esta é a solução de Keith Randall, implementada em Ruby.
fonte
C # 144/15 = 9,6
Isso passou em todos os testes.
Com menos caracteres, ele passa no TestU01.
Resultado: http://codepad.org/iny6usjV
fonte
C # - 103/14 = 7,36
Resultados
Passa em todos, exceto no teste nº 6
Veja os resultados em http://codepad.org/k1NSoyQW
Explicação
O C # simplesmente não pode competir com Ruby e Python pela concisão, como sempre, mas eu gostei de tentar. Certamente existem outros valores que também funcionarão (ou seja, o valor inicial para j = 999 e o divisor = 277). Eu os escolhi após uma breve experimentação.
Com wrapper de criação de arquivo
fonte
Python, 41/15 = 2.73333
É meio trapacear usando a função de hash embutida, mas é embutida, então não há mais trapaça do que usar outras embutidas, como
len
. Por outro lado, me dói ter que pagar pelaglobal v;
declaração ...Passa em todos os testes da Diehard (tive um problema com o teste nº 2, SEGVs na minha máquina OSX. Para minha pontuação, suponho que ele passará).
Aqui está um driver para gerar o arquivo de 16 MB:
fonte
+
uma função interna e, portanto, desqualificada?+
e__add__
em python, ou sobrecarga de operador em c ++. Eu sei que estou meio que quebrando cabelos, então considere este exemplo. Em python posso criar um mapa como este{'a':5}
:? Você provavelmente dirá que sim, mas considere que, debaixo das cobertas,hash('a')
é chamado quando você faz isso.C, 38/15 = 2,533
Não consegui que os testes Diehard funcionassem na minha máquina, mas ele passou no pacote PractRand com até 8 GB de saída, portanto presumo que passaria em todos eles.
fonte
Brain-Flak , 344 / (pendente)
Experimente online!
Isso funciona bem, mas os links de testes obstinados estão todos quebrados :( então, até obtermos novos, não tenho uma pontuação final
Isso usa o Blum Blum Shub PRNG, por isso deve passar na maioria dos casos. Os números usados são grandes o suficiente, nenhum padrão aparecerá nos 16 MB de casos de teste
fonte
Objetivo-C, 40/1 = 40
Abordagem bastante inteligente, explorando
.hash
para enganar um pouco aqui, mas eu gostofonte