A seguinte declaração de impressão imprimiria "olá mundo". Alguém poderia explicar isso?
System.out.println(randomString(-229985452) + " " + randomString(-147909649));
E randomString()
fica assim:
public static String randomString(int i)
{
Random ran = new Random(i);
StringBuilder sb = new StringBuilder();
while (true)
{
int k = ran.nextInt(27);
if (k == 0)
break;
sb.append((char)('`' + k));
}
return sb.toString();
}
n
nosfor (int n = 0; ; n++)
. Eles poderiam usarfor(;;)
ou emwhile(true)
vez disso!Respostas:
Quando uma instância de
java.util.Random
é construída com um parâmetro de semente específico (neste caso-229985452
ou-147909649
), segue o algoritmo de geração de número aleatório começando com esse valor de semente.Todo
Random
construído com a mesma semente gerará o mesmo padrão de números todas as vezes.fonte
"hello\0"
e"world\0"
. Se você assumisse um gerador verdadeiramente aleatório, as chances seriam de 1 em 27 ^ 6 (387.420.489) para obter a sequência que você estava procurando - portanto, é bastante impressionante, mas não é impressionante!"Hello"
"World"
), ou utilizando122-k
, em vez de96+k
, ou ...As outras respostas explicam o porquê, mas aqui está como.
Dada uma instância de
Random
:Os 6 primeiros números
r.nextInt(27)
gerados são:e os 6 primeiros números
r.nextInt(27)
geradosRandom r = new Random(-147909649)
são:Em seguida, basta adicionar esses números à representação inteira do caractere
`
(que é 96):fonte
new Random(-229985452).nextInt(27)
sempre retorna 8.new Random()
não retorna um número.Random
não é criptograficamente seguro (tenho certeza de que é um Mersenne Twister, mas não me cite nisso), provavelmente é possível trabalhar de trás para frente, de "Quero esses números" para "este é o semente que eu usaria ". Eu fiz algo semelhante com o gerador congruencial linear C padrão.Vou deixar aqui. Quem tiver muito tempo (CPU) de sobra, sinta-se à vontade para experimentar :) Além disso, se você dominou algum fork-join-fu para fazer essa coisa queimar todos os núcleos da CPU (apenas threads são chatos, certo?), Compartilhe seu código. Eu apreciaria muito.
Resultado:
fonte
nextInt(27)
significa dentro do intervalo[0, 26]
.Todo mundo aqui fez um ótimo trabalho explicando como o código funciona e mostrando como você pode construir seus próprios exemplos, mas aqui está uma resposta teórica da informação mostrando por que podemos razoavelmente esperar que exista uma solução que a pesquisa de força bruta acabará encontrando.
As 26 letras minúsculas diferentes formam nosso alfabeto
Σ
. Para permitir a geração de palavras de diferentes comprimentos, adicionamos ainda um símbolo terminador⊥
para gerar um alfabeto estendidoΣ' := Σ ∪ {⊥}
.Let
α
Ser um símbolo e X uma variável aleatória distribuída uniformemente sobreΣ'
. A probabilidade de obter esse símbolo,P(X = α)
e seu conteúdo informativoI(α)
, são dados por:Para uma palavra
ω ∈ Σ*
e sua⊥-
contraparte finalizadaω' := ω · ⊥ ∈ (Σ')*
, temosComo o gerador de números aleatórios pseudo-aleatórios (PRNG) é inicializado com uma semente de 32 bits, podemos esperar a maioria das palavras com comprimento de até
para ser gerado por pelo menos uma semente. Mesmo se procurássemos uma palavra de 6 caracteres, ainda teríamos sucesso em 41,06% do tempo. Não é muito pobre.
Em 7 letras, estamos olhando para mais perto de 1,52%, mas eu não tinha percebido isso antes de tentar:
Veja a saída: http://ideone.com/JRGb3l
fonte
I(⍵)
equação reorganizada.I(⍵)
é 32 (bits) e|⍵|
acaba sendo 5 (símbolos).Eu escrevi um programa rápido para encontrar essas sementes:
Eu tenho isso rodando em segundo plano agora, mas ele já encontrou palavras suficientes para um pangram clássico:
( Demonstração em ideone. )
Ps.
-727295876, -128911, -1611659, -235516779
.fonte
Fiquei intrigado com isso, corri esse gerador de palavras aleatórias em uma lista de palavras do dicionário. Intervalo: Integer.MIN_VALUE a Integer.MAX_VALUE
Eu tenho 15131 hits.
Impressões
fonte
A maioria dos geradores de números aleatórios é, de fato, "pseudo-aleatória". Eles são geradores lineares congruentes ou LCGs ( http://en.wikipedia.org/wiki/Linear_congruential_generator )
LCGs são bastante previsíveis, dada uma semente fixa. Basicamente, use uma semente que lhe dê sua primeira letra e, em seguida, escreva um aplicativo que continue a gerar o próximo int (char) até você acertar a próxima letra na string de destino e anote quantas vezes você precisou chamar o LCG. Continue até gerar todas as letras.
fonte
/dev/urandom
dispositivo para ler dados aleatórios. Este é um recurso escasso, no entanto. Portanto, esses dados aleatórios são normalmente usados para propagar PRNGs.urandom
ainda está pseudo-aleatório en.wikipedia.org/wiki//dev/random/dev/random
. O artigo que citei acima diz o kernel do Linux gera entropia a partir de tempos do teclado, movimentos do mouse e tempos do IDE e disponibiliza os dados aleatórios de caracteres para outros processos do sistema operacional através dos arquivos especiais / dev / random e / dev / urandom. Isso me permite acreditar que é realmente aleatório. Pode ser que não esteja totalmente correto. Mas/dev/random
pelo menos contém alguma entropia.Como o multi-threading é muito fácil com Java, aqui está uma variante que procura uma semente usando todos os núcleos disponíveis: http://ideone.com/ROhmTA
fonte
L
e alterar o tipo de argumento paralong
, ou sejarandomString(long i)
, para brincar. :)Aleatório sempre retorna a mesma sequência. É usado para embaralhar matrizes e outras operações como permutações.
Para obter sequências diferentes, é necessário inicializar a sequência em alguma posição, chamada "semente".
O randomSting obtém o número aleatório na posição i (semente = -229985452) da sequência "aleatória". Então usa o ASCII código para o próximo caractere 27 na sequência após a posição inicial até que esse valor seja igual a 0. Isso retorna o "hello". A mesma operação é feita para "mundo".
Eu acho que o código não funcionou para outras palavras. O cara que programou que conhece muito bem a sequência aleatória.
É um ótimo código nerd!
fonte
O principal é que a Classe Aleatória construída com a mesma semente gerará o mesmo padrão de números toda vez.
fonte
Derivado da resposta de Denis Tulskiy , esse método gera a semente.
fonte
Nos documentos Java, esse é um recurso intencional ao especificar um valor inicial para a classe Random.
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html
Estranho, você pensaria que existem problemas implícitos de segurança em ter números 'aleatórios' previsíveis.
fonte
Random
"define a semente do gerador de números aleatórios para um valor muito provável de ser distinto de qualquer outra invocação desse construtor" ( javadoc ). Na implementação atual, essa é uma combinação do horário atual e de um contador.É sobre "semente". As mesmas sementes dão o mesmo resultado.
fonte
Aqui está uma pequena melhoria para a resposta de Denis Tulskiy . Corta o tempo pela metade
fonte
Resultado
fonte