É possível propagar o gerador de números aleatórios (Math.random) em Javascript?
javascript
random
choroso
fonte
fonte
Respostas:
Não, não é, mas é bastante fácil escrever seu próprio gerador ou, melhor ainda, usar um já existente. Confira: esta questão relacionada .
Além disso, consulte o blog de David Bau para obter mais informações sobre propagação .
fonte
OBSERVAÇÃO: Apesar (ou melhor, por causa da) sucessão e elegância aparente, esse algoritmo não é de forma alguma de alta qualidade em termos de aleatoriedade. Procure, por exemplo, os listados nesta resposta para obter melhores resultados.
(Originalmente adaptado de uma ideia inteligente apresentada em um comentário para outra resposta.)
Você pode definir
seed
qualquer número, evite zero (ou qualquer múltiplo de Math.PI).A elegância dessa solução, na minha opinião, vem da falta de números "mágicos" (além de 10000, que representa a quantidade mínima de dígitos que você deve jogar fora para evitar padrões estranhos - veja resultados com os valores 10 , 100 , 1000 ) Brevidade também é legal.
É um pouco mais lento que Math.random () (por um fator de 2 ou 3), mas acredito que seja tão rápido quanto qualquer outra solução escrita em JavaScript.
fonte
Eu implementei uma série de boas, curtas e rápidas funções gerador de números Pseudoaleatórios (PRNG) em JavaScript simples. Todos eles podem ser semeados e fornecer números de boa qualidade.
Antes de tudo, tome cuidado para inicializar seus PRNGs corretamente.A maioria dos geradores abaixo não possui procedimento de geração de sementes embutido (por uma questão de simplicidade), mas aceita um ou mais valores de 32 bits como estado inicial do PRNG. Sementes similares (por exemplo, uma semente simples de 1 e 2) podem causar correlações em PRNGs mais fracos, resultando em resultados com propriedades semelhantes (como níveis gerados aleatoriamente sendo semelhantes). Para evitar isso, é uma boa prática inicializar PRNGs com uma semente bem distribuída.
Felizmente, as funções de hash são muito boas para gerar sementes para PRNGs a partir de strings curtas. Uma boa função de hash gera resultados muito diferentes, mesmo quando duas seqüências são semelhantes. Aqui está um exemplo baseado na função de mixagem do MurmurHash3:
Cada chamada subseqüente à função de retorno
xmur3
produz um novo valor de hash "aleatório" de 32 bits para ser usado como uma semente em um PRNG. Veja como você pode usá-lo:Como alternativa, basta escolher alguns dados fictícios para preencher a semente e avançar o gerador algumas vezes (12 a 20 iterações) para misturar completamente o estado inicial. Isso geralmente é visto em implementações de referência de PRNGs, mas limita o número de estados iniciais.
A saída dessas funções PRNG produz um número positivo de 32 bits (0 a 2 32 -1), que é convertido em um número de ponto flutuante entre 0-1 (0 inclusivo, 1 exclusivo) equivalente a
Math.random()
, se você quiser números aleatórios de um intervalo específico, leia este artigo no MDN . Se você deseja apenas os bits brutos, basta remover a operação de divisão final.Outra coisa a se notar são as limitações do JS. Os números podem representar apenas números inteiros até a resolução de 53 bits. E ao usar operações bit a bit, isso é reduzido para 32. Isso dificulta a implementação de algoritmos escritos em C ou C ++, que usam números de 64 bits. Portar código de 64 bits requer calços que podem reduzir drasticamente o desempenho. Portanto, por uma questão de simplicidade e eficiência, considerei apenas algoritmos que usam matemática de 32 bits, pois é diretamente compatível com JS.
sfc32 (contador rápido simples)
O sfc32 faz parte do conjunto de testes de números aleatórios PractRand (que é aprovado, é claro). O sfc32 possui um estado de 128 bits e é muito rápido em JS.
Mulberry32
O Mulberry32 é um gerador simples com um estado de 32 bits, mas é extremamente rápido e tem boa qualidade (o autor declara que passa em todos os testes do conjunto de testes gjrand e possui um período completo de 32 32 , mas não verifiquei).
Eu recomendaria isso se você só precisa de um PRNG simples, mas decente, e não precisa de bilhões de números aleatórios (consulte Problema no aniversário ).
xoshiro128 **
A partir de maio de 2018, xoshiro128 ** é o novo membro da família Xorshift , de Vigna / Blackman (que também escreveu xoroshiro, usado no Chrome). É o gerador mais rápido que oferece um estado de 128 bits.
Os autores afirmam que passam bem nos testes de aleatoriedade ( embora com ressalvas ). Outros pesquisadores apontaram que falha em alguns testes no TestU01 (particularmente LinearComp e BinaryRank). Na prática, não deve causar problemas quando são utilizados carros alegóricos (como essas implementações), mas pode causar problemas se depender dos bits baixos brutos.
JSF (jejum pequeno de Jenkins)
Esse é o JSF ou 'smallprng' de Bob Jenkins (2007), o cara que criou o ISAAC e o SpookyHash . Ele passa nos testes do PractRand e deve ser bastante rápido, embora não tão rápido quanto o SFC.
LCG (também conhecido como Lehmer / Park-Miller RNG ou MCG)
O LCG é extremamente rápido e simples, mas a qualidade de sua aleatoriedade é tão baixa que o uso inadequado pode realmente causar bugs no seu programa! No entanto, é significativamente melhor do que algumas respostas sugerindo o uso
Math.sin
ouMath.PI
! É uma frase única, o que é legal :).Essa implementação é chamada de RNG padrão mínimo, conforme proposto por Park-Miller em 1988 e 1993 e implementado no C ++ 11 como
minstd_rand
. Lembre-se de que o estado é de 31 bits (31 bits fornecem 2 bilhões de estados possíveis, 32 bits fornecem o dobro disso). Este é o tipo de PRNG que outros estão tentando substituir!Funcionará, mas eu não o usaria a menos que você realmente precise de velocidade e não se importe com a qualidade da aleatoriedade (o que é aleatório, afinal?). Ótimo para um game jam ou uma demo ou algo assim. Os LCGs sofrem correlações de sementes, portanto, é melhor descartar o primeiro resultado de um LCG. E se você insistir em usar um LCG, adicionar um valor de incremento pode melhorar os resultados, mas provavelmente é um exercício de futilidade quando existem opções muito melhores.
Parece haver outros multiplicadores que oferecem um estado de 32 bits (maior espaço de estado):
Esses valores de LCG são de: P. L'Ecuyer: Uma tabela de Geradores Lineares Congruenciais de diferentes tamanhos e boa estrutura de treliça, 30 de abril de 1997.
fonte
seed = (seed * 185852 + 1) % 34359738337
.Math.imul
permite que ele transborde como faria ao usar a multiplicação em C em números inteiros de 32 bits. O que você está sugerindo é um LCG utilizando toda a gama de espaço inteiro do JS, que também é definitivamente uma área interessante para explorar. :)Não, mas aqui está um simples gerador de pseudo-aleatório, uma implementação do Multiply-with-carry I adaptada da Wikipedia (foi removida desde):
EDIT: função de semente corrigida, redefinindo m_z
EDIT2: falhas graves de implementação foram corrigidas
fonte
seed
função não redefine o gerador aleatório, porque amz_z
variável é alterada quandorandom()
é chamada. Portanto definidomz_z = 987654321
(ou qualquer outro valor) emseed
m_w
, nãom_z
. 2) Ambosm_w
em_z
são alterados com base em seus valores anteriores, portanto modificam o resultado.O algoritmo de Antti Sykäri é bom e curto. Inicialmente, fiz uma variação que substituiu Math.random do Javascript quando você chama Math.seed (s), mas Jason comentou que retornar a função seria melhor:
Isso fornece outra funcionalidade que o Javascript não possui: vários geradores aleatórios independentes. Isso é especialmente importante se você quiser ter várias simulações repetíveis em execução ao mesmo tempo.
fonte
Math.random
que permitiria ter vários geradores independentes, certo?Math.seed(42);
, redefine a função; portanto, sevar random = Math.seed(42); random(); random();
você conseguir0.70...
,0.38...
. Se você redefini-la, chamandovar random = Math.seed(42);
novamente, então da próxima vez que você chamarrandom()
você vai ter0.70...
outra vez, e da próxima vez que você vai ter0.38...
novamente.random
vez de substituir uma função javascript nativa. A substituiçãoMath.random
pode fazer com que o compilador JIST des otimize todo o seu código.Por favor, veja o trabalho de Pierre L'Ecuyer desde o final dos anos 80 e início dos anos 90. Há outros também. Criar um gerador de números aleatórios (pseudo) por conta própria, se você não for um especialista, é muito perigoso, porque há uma alta probabilidade de os resultados não serem estatisticamente aleatórios ou terem um período pequeno. Pierre (e outros) reuniram alguns bons (pseudo) geradores de números aleatórios que são fáceis de implementar. Eu uso um de seus geradores LFSR.
https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf
Phil Troy
fonte
Combinando algumas das respostas anteriores, esta é a função aleatória inicial que você está procurando:
fonte
Math.seed(0)()
retornos0.2322845458984375
eMath.seed(1)()
retornos0.23228873685002327
. Mudar os doism_w
e dem_z
acordo com a semente parece ajudar.var m_w = 987654321 + s; var m_z = 123456789 - s;
produz uma boa distribuição dos primeiros valores com sementes diferentes.Escrever seu próprio gerador pseudo-aleatório é bastante simples.
A sugestão de Dave Scotese é útil, mas, como apontado por outros, não é distribuída de maneira uniforme.
No entanto, não é por causa dos argumentos inteiros do pecado. É simplesmente por causa do alcance do pecado, que passa a ser uma projeção unidimensional de um círculo. Se você escolher o ângulo do círculo, ele será uniforme.
Portanto, em vez de sin (x), use arg (exp (i * x)) / (2 * PI).
Se você não gosta da ordem linear, misture um pouco com xor. O fator real também não importa tanto.
Para gerar n números pseudo-aleatórios, pode-se usar o código:
Observe também que você não pode usar sequências pseudo-aleatórias quando a entropia real for necessária.
fonte
Atualmente, muitas pessoas que precisam de um gerador de números aleatórios sem fio em Javascript estão usando o módulo aleatório de sementes de David Bau .
fonte
Math.random
não, mas a biblioteca executada resolve isso. Ele tem quase todas as distribuições que você pode imaginar e suporta a geração de números aleatórios semeados. Exemplo:fonte
Eu escrevi uma função que retorna um número aleatório semeado, ele usa Math.sin para ter um número aleatório longo e usa a semente para escolher números disso.
Usar :
retornará seu número inicial, o primeiro parâmetro é qualquer valor de string; sua semente. o segundo parâmetro é quantos dígitos retornarão.
fonte
Uma abordagem simples para uma semente fixa:
fonte
Para um número entre 0 e 100.
fonte
Math.random
modo que, sempre que forMath.random
semeada com a mesma semente, ela produzirá a mesma série sucessiva de números aleatórios. Esta questão não é, por exemplo, sobre o uso / demonstração real deMath.random
.