Inspirado pela Random com as mãos atadas :
O objetivo
O objetivo desse desafio é escrever um programa que gere um fluxo de bits pseudo-aleatório, que é uma sequência de 1s e 0s que parece ser puramente aleatória, mas que na verdade é gerada de maneira determinística. Seu programa deve gerar uma sequência de 1 e 0s (com espaço em branco opcional) e deve passar os seguintes requisitos:
- Com tempo e memória ilimitados, seu programa deve continuar produzindo uma sequência de 1s e 0s para sempre
- Seu programa deve gerar mais de 1000 bits aleatórios em aproximadamente um minuto, em uma máquina razoável. Se esse requisito for impossível, eu o diminuirei.
- A sequência de bits pode se repetir, mas o comprimento da seção de repetição deve ser superior a 1000 bits.
- A sequência de bits deve passar no maior número possível de testes de aleatoriedade (descritos abaixo).
- O programa não deve receber nenhuma entrada de fontes externas ou usar qualquer função rand () integrada.
- Devido ao requisito acima, o programa deve gerar a mesma seqüência exata de bits cada vez que é executado.
Teste de aleatoriedade # 1
A sequência de bits pseudo-aleatórios não deve incluir nenhum padrão óbvio na inspeção visual.
Teste de aleatoriedade # 2 (sujeito a alterações com base nos comentários)
A cadeia de bits deve conter uma distribuição igual de 1s e 0s. Para testar isso (e outras coisas também), o fluxo de bits é dividido em segmentos com 3 bits, como 101|111|001
.
De todos esses segmentos, 1/8 deles deve ter três 1s e nenhum 0s, 3/8 deles devem ter dois 1s e um 0, 3/8 deles devem ter um 1 e dois 0s e 1/8 deles não devem ter 1s e três 0s.
Teste de aleatoriedade # 3
Uma "execução" é definida como uma série consecutiva de bits que todos têm o mesmo valor. A cadeia 1001001110
possui três execuções do tamanho 1 ( 1..1.....0
), duas execuções do tamanho 2 ( .00.00....
) e uma execução do tamanho 3 ( ......111.
). Observe que as execuções não se sobrepõem.
De uma sequência de 1000 bits aleatórios, deve haver cerca de 250 execuções do tamanho 1, 125 execuções do tamanho 2, 62 execuções do tamanho 3, etc. Em geral, para o tamanho da execução R, deve haver aproximadamente 1000/(2**(R+1))
execuções desse tamanho.
Teste de aleatoriedade # 4
Os primeiros 840 bits são divididos em duas metades de 420 bits cada. Cada bit na primeira metade é comparado ao bit correspondente na segunda metade. Os dois bits devem corresponder cerca de cinquenta por cento do tempo.
Aqui está o código fonte de um programa Perl que executa os testes 2 a 4. A partir de agora, ele exige que a sequência de bits não contenha nenhum espaço em branco.
Tempo de critério de vencimento objetivo!
O vencedor é o programa que passa todos os 6 requisitos e todos os testes de aleatoriedade na medida em que é indistinguível da aleatoriedade. Se vários programas conseguirem isso, o que levar mais tempo para repetir vencerá. Se vários programas conseguirem isso, talvez seja necessário encontrar mais testes de aleatoriedade para atuar como desempate.
fonte
Respostas:
C, 61
Sim, eu sei que não é código de golfe. Obviamente, isso é uma anti-solução ... mas com certeza atende aos seus critérios.
A duração do período é 2²⁹.
fonte
Mathematica
7853 caracteresOs dígitos da representação binária de Pi parecem se comportar como se fossem produzidos caoticamente, embora isso não seja comprovado.
A rotina simples a seguir retorna deterministicamente como uma sequência os dígitos binários de pi, correspondentes aos
d
dígitos decimais:Uso
Se solicitarmos a contrapartida de 301 dígitos decimais de Pi, receberemos 1000 dígitos binários.
Como Pi é um número irracional, não há período. No entanto, haverá restrições práticas devido ao hardware que está sendo executado.
Teste 1 Parece bom para mim.
Teste 2
Verificação mais completa:
Teste 3: Executa
Eu executei um grande número de casos para verificar sistematicamente a distribuição de execuções. Em aproximadamente 3 milhões de dígitos binários, havia 830k execuções de 1, 416k execuções de 2, 208k execuções de 3, 104k execuções de 4, etc.
Teste 4: correspondência da primeira e da segunda metade dos dados
As correspondências são os 212 casos de 0 e 2; as incompatibilidades são os 208 casos em que a soma dos respectivos dígitos é 1.
Cronometragem
Demora menos de dois segundos para calcular 3321928 dígitos binários (correspondentes a 10 ^ 6 dígitos decimais).
fonte
e
vez depi
salvar um byte?e
distribuído caoticamente?Python, 90
g
é o valor inicial. A amostragem aleatória exibe uma distribuição notavelmente normal. A amostragem aleatória repetida das médias da amostra produziu uma média0.506
e um desvio padrão de.0473
(tamanho da amostra de 1000). Infelizmente, a aleatoriedade é altamente sensível à semente inicial. A semente no código acima me deu a melhor aleatoriedade: pATUALIZAR
Vamos ver como esse código aguenta os testes do OP:
Teste # 1
Este é um pouco subjetivo ... mas me parece bastante irregular.
Teste # 2
Teste # 3
Executa por tamanho:
Teste # 4
fonte
Haskell
7458Obrigado a shiona pela simplificação. Resultados:
Este também é um terrível gerador pseudo-aleatório (semelhante ao usado por von-Neuman). Para aqueles que não estavam cientes
concatMap == (=<<) == flip . (>>=)
(para listas)fonte
\x->if odd x then"1"else"0"
porshow.(`mod`2)
.A questão é essencialmente equivalente a "implementar uma cifra de fluxo". Por isso, implementei o RC4, pois é relativamente simples.
Não uso nenhuma chave e largo os primeiros 100000 bits, porque o início do RC4 é um pouco tendencioso, principalmente porque ignorei o cronograma das chaves. Mas eu esperaria que ele passasse no teste mesmo sem isso (economizando 20 caracteres de código).
Normalmente, seria gerado um byte completo por ciclo, mas a conversão para binário é bastante feia em C #, então simplesmente descarto tudo, exceto o bit menos significativo.
Ou sem espaços:
C #, 156 caracteres, funciona no modo de instrução do LinqPad. Para um programa C # completo, adicione o padrão comum.
Também poderíamos usar primitivas criptográficas incorporadas (solução Cheater):
(C #, 99 caracteres, funciona no modo de instrução do LinqPad. Para o compilador C # normal, você precisará adicionar um pouco de clichê)
A saída das funções de hash criptográfico é projetada para ser indistinguível de dados aleatórios, então eu espero que ela passe em todos os testes de aleatoriedade (morra mais forte, ...) que você joga nela, mas estou com preguiça de testar.
fonte
C, 52 caracteres
Este é um LFSR de 10 bits, resultados do teste:
fonte
a
deve começar como 1, (supondo que seja chamado sem argumentos). Além disso, você pode furar oa=
no meio, algo comoa=a/2^-!putchar(49-a%2)%576
(tendo algumas liberdades com o algoritmo)a
, eu a mudei por causa de "The program must not take any input from any external sources
"Sage / Python
Este programa imprime os dígitos binários mais à direita, comuns a todas as torres de exponenciação suficientemente altas, no formato 3 3 3 3 . . . Por tudo o que poderia ser gerado de maneira viável, esses são os dígitos binários mais à direita do número de Graham . A sequência de dígitos é infinita e não é periódica.
Para 1000 dígitos, isso levou menos de 2 segundos; no entanto, o tempo aumentará muito mais rápido do que linearmente no número de dígitos.
Os resultados do teste usando o programa do OP são
(Consulte Os dígitos mais à direita de G são aleatórios? Para mais de 32000 dígitos e testes estatísticos adicionais.)
fonte
Java,
371317Com base em um LFSR de 128 bits (os toques de bits são do xilinx app note 52 )
Edição: Eu não estava satisfeito com o uso do BigInteger, então esta versão não. Salvou alguns caracteres. A saída pode ser um pouco menos aleatória, pois eu não conseguia pensar em um bom método de 'propagação'.
Novo código: Argumentos: BITS_TO_PRINT
Versão antiga: Argumentos: SEED, BITS_TO_PRINT
Nova versão: Exemplo de saída, bits = 100:
fonte
JavaScript - 1ms a 2ms para 1000 bits pseudo-aleatórios (139ms a 153ms para 100000 bits)
Essa solução usa o fato de que as raízes quadradas são irracionais e, portanto, praticamente aleatórias. Basicamente, é necessária a raiz quadrada de 2 para iniciar, a converte em binária, joga fora a parte principal que corresponde à raiz anterior, anexa à seqüência aleatória, repete com o próximo número mais alto (ou volta a 2 se o número repetido e tinha pelo menos 30 bits) e retorna a sequência aleatória assim que for longa o suficiente.
Ainda não testei os testes, mas imagino que funcione bem neles. Aqui está um violino para que você possa vê-lo em ação. Nos meus tempos, apenas executei o programa várias vezes e assumi os valores mais rápidos e lentos como os intervalos.
fonte
Pitão
Deve ter um período de cerca de 2 ^ 512.
fonte
perl, 44 bytes
Eu sei que isso não é código de golfe, mas sempre fui fã de pegar os bits de baixa ordem de uma função quadrática simples, por exemplo:
O período é superior a 3 bilhões, mas fiquei sem espaço em disco para calcular mais.
fonte
$x=1/7;print substr($x*=4-4*$x,9,1)%2while 1