¿Es posible sembrar el generador de números aleatorios (Math.random) en Javascript?
javascript
random
llorón
fuente
fuente
Respuestas:
No, no lo es, pero es bastante fácil escribir su propio generador, o mejor aún usar uno existente. Echa un vistazo: esta pregunta relacionada .
Además, vea el blog de David Bau para obtener más información sobre la siembra .
fuente
NOTA: A pesar de (o más bien, debido a) la concisión y la elegancia aparente, este algoritmo no es de ninguna manera de alta calidad en términos de aleatoriedad. Busque, por ejemplo, los que figuran en esta respuesta para obtener mejores resultados.
(Originalmente adaptado de una idea inteligente presentada en un comentario a otra respuesta).
Puede establecer
seed
cualquier número, solo evite cero (o cualquier múltiplo de Math.PI).La elegancia de esta solución, en mi opinión, proviene de la falta de números "mágicos" (además de 10000, que representa aproximadamente la cantidad mínima de dígitos que debe tirar para evitar patrones extraños; vea los resultados con valores 10 , 100 , 1000 ) La brevedad también es agradable.
Es un poco más lento que Math.random () (por un factor de 2 o 3), pero creo que es casi tan rápido como cualquier otra solución escrita en JavaScript.
fuente
He implementado varias funciones buenas, cortas y rápidas de generador de números pseudoaleatorios (PRNG) en JavaScript simple. Todos ellos pueden sembrarse y proporcionar números de buena calidad.
En primer lugar, tenga cuidado de inicializar sus PRNG correctamente. La mayoría de los generadores a continuación no tienen un procedimiento de generación de semillas incorporado (por simplicidad), pero aceptan uno o más valores de 32 bits como el estado inicial del PRNG. Semillas similares (por ejemplo, una semilla simple de 1 y 2) pueden causar correlaciones en PRNG más débiles, lo que da como resultado que la salida tenga propiedades similares (como que los niveles generados aleatoriamente sean similares). Para evitar esto, es una buena práctica inicializar los PRNG con una semilla bien distribuida.
Afortunadamente, las funciones hash son muy buenas para generar semillas para PRNG a partir de cadenas cortas. Una buena función hash generará resultados muy diferentes incluso cuando dos cadenas sean similares. Aquí hay un ejemplo basado en la función de mezcla de MurmurHash3:
Cada llamada posterior a la función de retorno de
xmur3
produce un nuevo valor hash "aleatorio" de 32 bits que se utilizará como semilla en un PRNG. Así es como puede usarlo:Alternativamente, simplemente elija algunos datos ficticios para rellenar la semilla y avance el generador varias veces (12-20 iteraciones) para mezclar bien el estado inicial. Esto se ve a menudo en implementaciones de referencia de PRNG, pero limita el número de estados iniciales.
La salida de estas funciones PRNG produce un número positivo de 32 bits (0 a 2 32 -1) que luego se convierte en un número de coma flotante entre 0-1 (0 inclusive, 1 exclusivo) equivalente a
Math.random()
, si desea números aleatorios de un rango específico, lea este artículo en MDN . Si solo desea los bits sin procesar, simplemente elimine la operación de división final.Otra cosa a tener en cuenta son las limitaciones de JS. Los números solo pueden representar enteros enteros de hasta 53 bits de resolución. Y cuando se utilizan operaciones bit a bit, esto se reduce a 32. Esto dificulta la implementación de algoritmos escritos en C o C ++, que usan números de 64 bits. Portar código de 64 bits requiere cuñas que pueden reducir drásticamente el rendimiento. Entonces, por simplicidad y eficiencia, solo he considerado algoritmos que usan matemáticas de 32 bits, ya que es directamente compatible con JS.
sfc32 (Contador rápido simple)
sfc32 es parte del conjunto de pruebas de números aleatorios PractRand (que, por supuesto, pasa). sfc32 tiene un estado de 128 bits y es muy rápido en JS.
Mulberry32
Mulberry32 es un generador simple con un estado de 32 bits, pero es extremadamente rápido y de buena calidad (el autor declara que pasa todas las pruebas de gjrand testing suite y tiene un período completo de 2 32 , pero no lo he verificado).
Lo recomendaría si solo necesita un PRNG simple pero decente y no necesita miles de millones de números aleatorios (consulte Problema de cumpleaños ).
xoshiro128 **
A partir de mayo de 2018, xoshiro128 ** es el nuevo miembro de la familia Xorshift , de Vigna / Blackman (quien también escribió xoroshiro, que se usa en Chrome). Es el generador más rápido que ofrece un estado de 128 bits.
Los autores afirman que pasa bien las pruebas de aleatoriedad ( aunque con advertencias ). Otros investigadores han señalado que falla algunas pruebas en TestU01 (particularmente LinearComp y BinaryRank). En la práctica, no debería causar problemas cuando se utilizan flotadores (como estas implementaciones), pero puede causar problemas si se confía en los bits bajos sin procesar.
JSF (pequeño ayuno de Jenkins)
Este es JSF o 'smallprng' de Bob Jenkins (2007), el tipo que creó ISAAC y SpookyHash . Se pasa las pruebas PractRand y debe ser bastante rápido, aunque no tan rápido como SFC.
LCG (también conocido como Lehmer / Park-Miller RNG o MCG)
LCG es extremadamente rápido y simple, pero la calidad de su aleatoriedad es tan baja que el uso incorrecto puede causar errores en su programa. Sin embargo, ¡es significativamente mejor que algunas respuestas que sugieren usar
Math.sin
oMath.PI
! Sin embargo, es una frase, lo cual es bueno :).Esta implementación se denomina RNG estándar mínimo según lo propuesto por Park-Miller en 1988 y 1993 y se implementa en C ++ 11 como
minstd_rand
. Tenga en cuenta que el estado es de 31 bits (31 bits dan 2 mil millones de estados posibles, 32 bits dan el doble de eso). ¡Este es el tipo de PRNG que otros están tratando de reemplazar!Funcionará, pero no lo usaría a menos que realmente necesite velocidad y no le importe la calidad de la aleatoriedad (¿qué es al azar de todos modos?). Genial para un juego jam o una demo o algo así. Los LCG sufren correlaciones de semillas, por lo que es mejor descartar el primer resultado de un LCG. Y si insiste en usar un LCG, agregar un valor de incremento puede mejorar los resultados, pero probablemente sea un ejercicio inútil cuando existen opciones mucho mejores.
Parece que hay otros multiplicadores que ofrecen un estado de 32 bits (mayor espacio de estado):
Estos valores LCG son de: P. L'Ecuyer: una tabla de generadores congruentes lineales de diferentes tamaños y buena estructura reticular, 30 de abril de 1997.
fuente
seed = (seed * 185852 + 1) % 34359738337
.Math.imul
permite desbordarse como lo haría al usar la multiplicación en C en enteros de 32 bits. Lo que está sugiriendo es un LCG que utiliza la gama completa del espacio entero de JS, que definitivamente es un área interesante para explorar también. :)No, pero aquí hay un generador pseudoaleatorio simple, una implementación de Multiplicar con acarreo que adapté de Wikipedia (se ha eliminado desde entonces):
EDIT: fija la función de semilla por lo que es restablecer m_z
Edit2: defectos graves de ejecución se han fijado
fuente
seed
función no restablece el generador aleatorio, porque lamz_z
variable cambia cuandorandom()
se llama. Por lo tanto, establezcamz_z = 987654321
(o cualquier otro valor) enseed
m_w
, nom_z
. 2) Ambosm_w
ym_z
se cambian BASADOS en sus valores anteriores, por lo que modifica el resultado.El algoritmo de Antti Sykäri es agradable y corto. Inicialmente hice una variación que reemplazó Math.random de Javascript cuando llamas a Math.seed (s), pero luego Jason comentó que devolver la función sería mejor:
Esto le brinda otra funcionalidad que Javascript no tiene: múltiples generadores aleatorios independientes. Eso es especialmente importante si desea tener múltiples simulaciones repetibles ejecutándose al mismo tiempo.
fuente
Math.random
eso le permitiría tener múltiples generadores independientes, ¿verdad?Math.seed(42);
se restablece la función, así que si novar random = Math.seed(42); random(); random();
se obtiene0.70...
, a continuación0.38...
. Si lo reinicia llamando devar random = Math.seed(42);
nuevo, la próxima vez que llamerandom()
recibirá de0.70...
nuevo y la próxima vez que lo haga0.38...
.random
lugar de sobrescribir una función de JavaScript nativa. La sobrescrituraMath.random
puede hacer que el compilador JIST no optimice todo su código.Vea el trabajo de Pierre L'Ecuyer que se remonta a finales de los años ochenta y principios de los noventa. Hay otros también. Crear un generador de números (pseudo) aleatorio por su cuenta, si no es un experto, es bastante peligroso, porque existe una alta probabilidad de que los resultados no sean estadísticamente aleatorios o que tengan un período pequeño. Pierre (y otros) han reunido algunos buenos (pseudo) generadores de números aleatorios que son fáciles de implementar. Yo uso uno de sus generadores LFSR.
https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf
Phil Troy
fuente
Combinando algunas de las respuestas anteriores, esta es la función aleatoria visible que está buscando:
fuente
Math.seed(0)()
devoluciones0.2322845458984375
yMath.seed(1)()
devoluciones0.23228873685002327
. Cambiar ambosm_w
y dem_z
acuerdo con la semilla parece ayudar.var m_w = 987654321 + s; var m_z = 123456789 - s;
produce una buena distribución de los primeros valores con diferentes semillas.Escribir su propio generador pseudoaleatorio es bastante simple.
La sugerencia de Dave Scotese es útil pero, como han señalado otros, no está distribuida de manera uniforme.
Sin embargo, no se debe a los argumentos enteros del pecado. Es simplemente por el rango del pecado, que resulta ser una proyección unidimensional de un círculo. Si tomas el ángulo del círculo, sería uniforme.
Entonces, en lugar de sin (x) use arg (exp (i * x)) / (2 * PI).
Si no te gusta el orden lineal, mézclalo un poco con xor. El factor real tampoco importa tanto.
Para generar n números seudoaleatorios, se podría usar el código:
Tenga en cuenta también que no puede usar secuencias pseudoaleatorias cuando se necesita una entropía real.
fuente
Muchas personas que necesitan un generador de números aleatorios visibles en Javascript en estos días están utilizando el módulo de semilla aleatoria de David Bau .
fuente
Math.random
no, pero la biblioteca ejecutada resuelve esto. Tiene casi todas las distribuciones que puedas imaginar y admite la generación de números aleatorios sembrados. Ejemplo:fuente
He escrito una función que devuelve un número aleatorio sembrado, usa Math.sin para tener un número aleatorio largo y usa la semilla para elegir números de eso.
Utilizar :
devolverá su número sembrado; el primer parámetro es cualquier valor de cadena; tu semilla El segundo parámetro es cuántos dígitos volverán.
fuente
Un enfoque simple para una semilla fija:
fuente
Para un número entre 0 y 100.
fuente
Math.random
modo que siempre queMath.random
se siembra con la misma semilla, produzca la misma serie sucesiva de números aleatorios. Esta pregunta no es, por decir, sobre el uso / demostración real deMath.random
.