A Math.random()
função JavaScript retorna um valor aleatório entre 0 e 1, semeado automaticamente com base no horário atual (semelhante ao Java, acredito). No entanto, acho que não há como definir sua própria semente.
Como posso criar um gerador de números aleatórios para o qual posso fornecer meu próprio valor inicial, para que ele produza uma sequência repetível de (pseudo) números aleatórios?
javascript
random
seed
scunliffe
fonte
fonte
Respostas:
Uma opção é http://davidbau.com/seedrandom, que é um substituto substituto do Math.random () baseado em RC4 e com boas propriedades.
fonte
Se você não precisar da capacidade de propagação, use
Math.random()
e crie funções auxiliares em torno dela (por exemplorandRange(start, end)
).Não sei ao certo qual RNG você está usando, mas é melhor conhecê-lo e documentá-lo para que você esteja ciente de suas características e limitações.
Como Starkii disse, Mersenne Twister é um bom PRNG, mas não é fácil de implementar. Se você quiser fazer isso, tente implementar um LCG - é muito fácil, possui qualidades de aleatoriedade decentes (não tão boas quanto Mersenne Twister), e você pode usar algumas das constantes populares.
EDIT: considere as ótimas opções nesta resposta para implementações de RNG semeadas curtas, incluindo uma opção de LCG.
fonte
this.a * this.state
é provável que resulte em um número maior que 2 ^ 53. O resultado é uma faixa de produção limitada e, para algumas sementes, possivelmente um período muito curto. Além disso, em geral, usando uma potência de dois param
resultar em alguns padrões bastante óbvios, quando você está gastando uma operação de módulo em vez de um simples truncamento de qualquer maneira, não há razão para não usar um primo.Se você deseja especificar a semente, basta substituir as chamadas
getSeconds()
egetMinutes()
. Você pode passar um int e usar metade dele mod 60 para o valor de segundos e a outra metade módulo 60 para dar a outra parte.Dito isto, esse método parece lixo. Fazer a geração apropriada de números aleatórios é muito difícil. O problema óbvio disso é que a semente do número aleatório é baseada em segundos e minutos. Para adivinhar a semente e recriar seu fluxo de números aleatórios, é necessário tentar 3600 combinações diferentes de segundo e minuto. Isso também significa que existem apenas 3600 diferentes sementes possíveis. Isso é corrigível, mas eu desconfiaria deste RNG desde o início.
Se você quiser usar um RNG melhor, tente o Mersenne Twister . É um RNG bem testado e bastante robusto, com uma órbita enorme e excelente desempenho.
Edição: Eu realmente deveria estar correto e me refiro a isso como um gerador de números pseudo-aleatórios ou PRNG.
fonte
Eu uso uma porta JavaScript do Mersenne Twister: https://gist.github.com/300494 Ele permite que você defina a semente manualmente. Além disso, como mencionado em outras respostas, o Mersenne Twister é realmente um bom PRNG.
fonte
O código que você listou parece um Lehmer RNG . Se for esse o caso, então
2147483647
é o maior número inteiro assinado de 32 bits,2147483647
o maior número primo de 32 bits e48271
um multiplicador de período completo usado para gerar os números.Se isso for verdade, você pode modificar
RandomNumberGenerator
para obter um parâmetro extraseed
e definirthis.seed
comoseed
; mas você deve ter cuidado para garantir que a semente resulte em uma boa distribuição de números aleatórios (Lehmer pode ser estranho assim) - mas a maioria das sementes ficará bem.fonte
A seguir, um PRNG que pode ser alimentado com uma semente personalizada. A chamada
SeedRandom
retornará uma função geradora aleatória.SeedRandom
pode ser chamado sem argumentos para propagar a função aleatória retornada com o tempo atual ou pode ser chamado com 1 ou 2 interseções não-negativas como argumentos para propiciar a propagação com esses números inteiros. Devido ao ponto de flutuação, a precisão da propagação com apenas 1 valor permitirá apenas que o gerador seja iniciado em um dos 2 ^ 53 estados diferentes.A função geradora aleatória retornada recebe 1 argumento inteiro nomeado
limit
; o limite deve estar no intervalo de 1 a 4294965886; a função retornará um número no intervalo de 0 ao limite 1.Exemplo de uso:
Este gerador exibe as seguintes propriedades:
mod
valores serem primos, não há um padrão simples na saída, independentemente do limite escolhido. Isso é diferente de alguns PRNGs mais simples que exibem alguns padrões bastante sistemáticos.fonte
for (var i = 0; i < 400; i++) { console.log("input: (" + i * 245 + ", " + i * 553 + ") | output: " + SeedRandom(i * 245, i * 553)(20)); }
Se você programar em Typescript, adaptei a implementação de Mersenne Twister que foi trazida na resposta de Christoph Henkelmann a este segmento como uma classe de texto datilografado:
você pode usá-lo da seguinte maneira:
verifique a fonte para mais métodos.
fonte
Eu encontrei esse código e parece funcionar bem para obter um número aleatório e depois usar a semente posteriormente, mas não tenho muita certeza de como a lógica funciona (por exemplo, de onde vieram os números 2345678901, 48271 e 2147483647).
fonte
RandomNumberGenerator
enextRandomNumber
realmente datam de 1996. Supõe-se que seja um Lehmer / LCG RNG. Ele usa algumas matemáticas inteligentes para executar aritmética modular em números inteiros de 32 bits que, de outra forma, seriam muito pequenos para conter alguns valores intermediários. O problema é que o JavaScript não implementa números inteiros de 32 bits, mas sim números flutuantes de 64 bits, e como a divisão não é uma divisão inteira, como esse código presume que o resultado não é um gerador Lehmer. Produz algum resultado que parece aleatório, mas as garantias de um gerador Lehmer não se aplicam.createRandomNumber
função é uma adição posterior, faz praticamente tudo de errado, principalmente instancia um novo RNG toda vez que é chamado, o que significa que as chamadas em sucessão rápida usarão o mesmo flutuador. No código fornecido, é quase impossível'a'
ser emparelhado com qualquer coisa, exceto'1'
e'red'
.OK, aqui está a solução que eu decidi.
Primeiro, você cria um valor inicial usando a função "newseed ()". Então você passa o valor inicial para a função "srandom ()". Por fim, a função "srandom ()" retorna um valor pseudo-aleatório entre 0 e 1.
O ponto crucial é que o valor inicial é armazenado dentro de uma matriz. Se fosse simplesmente um número inteiro ou float, o valor seria sobrescrito toda vez que a função fosse chamada, uma vez que os valores de números inteiros, floats, strings e assim por diante são armazenados diretamente na pilha versus apenas os ponteiros, como no caso de matrizes e outros objetos. Assim, é possível que o valor da semente permaneça persistente.
Finalmente, é possível definir a função "srandom ()" de modo que seja um método do objeto "Math", mas deixarei isso para você descobrir. ;)
Boa sorte!
JavaScript:
Lua 4 (meu ambiente de destino pessoal):
fonte
seedobj[0] * seedobja
é provável que resulte em um número maior que 2 ^ 53. O resultado é uma faixa de produção limitada e, para algumas sementes, possivelmente um período muito curto.