La Math.random()
función de JavaScript devuelve un valor aleatorio entre 0 y 1, sembrado automáticamente en función de la hora actual (similar a Java, creo). Sin embargo, no creo que haya ninguna forma de establecer su propia semilla para ello.
¿Cómo puedo hacer un generador de números aleatorios para el que pueda proporcionar mi propio valor inicial, de modo que pueda hacer que produzca una secuencia repetible de números (pseudo) aleatorios?
javascript
random
seed
scunliffe
fuente
fuente
Respuestas:
Una opción es http://davidbau.com/seedrandom, que es un reemplazo directo de Math.random () basado en RC4 visible con buenas propiedades.
fuente
Si no necesita la capacidad de siembra, simplemente use
Math.random()
y cree funciones auxiliares a su alrededor (p. Ej.randRange(start, end)
).No estoy seguro de qué RNG está utilizando, pero es mejor saberlo y documentarlo para que conozca sus características y limitaciones.
Como dijo Starkii, Mersenne Twister es un buen PRNG, pero no es fácil de implementar. Si desea hacerlo usted mismo, intente implementar un LCG : es muy fácil, tiene cualidades de aleatoriedad decentes (no tan buenas como Mersenne Twister) y puede usar algunas de las constantes populares.
EDITAR: considere las excelentes opciones en esta respuesta para implementaciones de RNG visibles cortas, incluida una opción LCG.
fuente
this.a * this.state
es probable que resulte en un número mayor que 2 ^ 53. El resultado es un rango de producción limitado, y para algunas semillas posiblemente un período muy corto. Además, en general, el uso de una potencia de dos param
dar como resultado algunos patrones bastante obvios, cuando se está gastando una operación de módulo en lugar de un simple truncamiento de todos modos, no hay razón para no usar un cebado.Si desea poder especificar la semilla, solo necesita reemplazar las llamadas a
getSeconds()
ygetMinutes()
. Puede pasar un int y usar la mitad del mod 60 para el valor de segundos y la otra mitad del módulo 60 para obtener la otra parte.Dicho esto, este método parece basura. Hacer la generación adecuada de números aleatorios es muy difícil. El problema obvio con esto es que el valor inicial aleatorio se basa en segundos y minutos. Para adivinar la semilla y recrear su flujo de números aleatorios solo requiere probar 3600 combinaciones diferentes de segundos y minutos. También significa que solo hay 3600 semillas diferentes posibles. Esto es corregible, pero sospecharía de este RNG desde el principio.
Si quieres usar un mejor RNG, prueba el Mersenne Twister . Es un RNG bien probado y bastante robusto con una órbita enorme y un rendimiento excelente.
EDITAR: Realmente debería ser correcto y referirme a esto como un generador de números pseudoaleatorios o PRNG.
fuente
Utilizo un puerto JavaScript del Mersenne Twister: https://gist.github.com/300494 Le permite configurar la semilla manualmente. Además, como se menciona en otras respuestas, el Mersenne Twister es un PRNG realmente bueno.
fuente
El código que enumeró se parece a un Lehmer RNG . Si este es el caso, entonces
2147483647
es el entero con signo más grande de 32 bits,2147483647
es el primo más grande de 32 bits y48271
es un multiplicador de período completo que se utiliza para generar los números.Si esto es cierto, puede modificar
RandomNumberGenerator
para incluir un parámetro adicionalseed
y luego configurarlothis.seed
enseed
; pero debe tener cuidado para asegurarse de que la semilla dé como resultado una buena distribución de números aleatorios (Lehmer puede ser así de extraño), pero la mayoría de las semillas estarán bien.fuente
El siguiente es un PRNG que puede alimentarse con una semilla personalizada. Llamar
SeedRandom
devolverá una función de generador aleatorio.SeedRandom
puede invocarse sin argumentos para inicializar la función aleatoria devuelta con la hora actual, o puede invocarse con 1 o 2 inters no negativos como argumentos para inicializar con esos enteros. Debido a la precisión de coma flotante, la siembra con solo 1 valor solo permitirá que el generador se inicie en uno de 2 ^ 53 estados diferentes.La función generadora aleatoria devuelta toma 1 argumento entero llamado
limit
, el límite debe estar en el rango de 1 a 4294965886, la función devolverá un número en el rango 0 al límite-1.Ejemplo de uso:
Este generador exhibe las siguientes propiedades:
mod
valores son primos, no hay un patrón simple en la salida, sin importar el límite elegido. Esto es diferente a algunos PRNG más simples que exhiben algunos patrones bastante sistemáticos.fuente
for (var i = 0; i < 400; i++) { console.log("input: (" + i * 245 + ", " + i * 553 + ") | output: " + SeedRandom(i * 245, i * 553)(20)); }
Si programa en mecanografiado, adapté la implementación de Mersenne Twister que fue presentada en la respuesta de Christoph Henkelmann a este hilo como una clase mecanografiada:
puede usarlo de la siguiente manera:
verifique la fuente para más métodos.
fuente
Encontré este código dando vueltas y parece funcionar bien para obtener un número aleatorio y luego usar la semilla después, pero no estoy muy seguro de cómo funciona la lógica (por ejemplo, de dónde provienen los números 2345678901, 48271 y 2147483647).
fuente
RandomNumberGenerator
ynextRandomNumber
realmente datan de 1996. Se supone que es un Lehmer / LCG RNG. Utiliza algunas matemáticas inteligentes para realizar módulos aritméticos en enteros de 32 bits que de otra forma serían demasiado pequeños para contener algunos valores intermedios. La cuestión es que JavaScript no implementa enteros de 32 bits, sino más bien flotantes de 64 bits, y dado que la división no es una división entera, como este código supone que el resultado no es un generador de Lehmer. Produce algún resultado que parece aleatorio, pero las garantías de un generador Lehmer no se aplican.createRandomNumber
función es una adición posterior, hace casi todo mal, más notablemente crea una instancia de un nuevo RNG cada vez que se llama, lo que significa que las llamadas en sucesión rápida usarán el mismo flotante. En el código dado, es casi imposible'a'
emparejarse con cualquier cosa que no sea'1'
y'red'
.OK, aquí está la solución que decidí.
Primero crea un valor semilla utilizando la función "newseed ()". Luego pasa el valor semilla a la función "srandom ()". Por último, la función "srandom ()" devuelve un valor pseudoaleatorio entre 0 y 1.
El bit crucial es que el valor semilla se almacena dentro de una matriz. Si se tratara simplemente de un entero o flotante, el valor se sobrescribiría cada vez que se llamara a la función, ya que los valores de enteros, flotantes, cadenas, etc. se almacenan directamente en la pila en lugar de solo los punteros como en el caso de las matrices y otros objetos Por lo tanto, es posible que el valor de la semilla permanezca persistente.
Finalmente, es posible definir la función "srandom ()" de tal manera que sea un método del objeto "Math", pero lo dejaré a usted para que lo descubra. ;)
¡Buena suerte!
JavaScript:
Lua 4 (mi entorno objetivo personal):
fuente
seedobj[0] * seedobja
es probable que resulte en un número mayor que 2 ^ 53. El resultado es un rango de producción limitado, y para algunas semillas posiblemente un período muy corto.