¿Qué tan aleatorio es Math.random de JavaScript?

116

Durante 6 años he tenido una página generadora de números aleatorios en mi sitio web. Durante mucho tiempo, fue el primer o segundo resultado en Google para "generador de números aleatorios" y se ha utilizado para decidir decenas, si no cientos de concursos y dibujos en foros de discusión y blogs (lo sé porque veo las referencias en mi registros web y, por lo general, ve a echar un vistazo).

Hoy, alguien me envió un correo electrónico para decirme que puede que no sea tan aleatorio como pensaba. Intentó generar números aleatorios muy grandes (por ejemplo, entre 1 y 10000000000000000000) y descubrió que casi siempre tenían el mismo número de dígitos. De hecho, envolví la función en un bucle para poder generar miles de números y, efectivamente, para números muy grandes, la variación fue de solo 2 órdenes de magnitud.

¿Por qué?

Aquí está la versión en bucle, para que pueda probarla usted mismo:

http://andrew.hedges.name/experiments/random/randomness.html

Incluye tanto una implementación sencilla tomada de Mozilla Developer Network como un código de 1997 que borré de una página web que ya no existe ("Central Randomizer 1.3" de Paul Houle). Ver fuente para ver cómo funciona cada método.

He leído aquí y en otros lugares sobre Mersenne Twister. Lo que me interesa es por qué no habría una mayor variación en los resultados de la función Math.random incorporada de JavaScript . ¡Gracias!

Andrew Hedges
fuente
"sarnath'd" como en, golpeado hasta el final, o en este caso, la respuesta
maetl
5
Si está buscando la respuesta a la pregunta en el título, consulte stackoverflow.com/questions/2344312/…
Andrew B.

Respuestas:

182

Dados números entre 1 y 100.

  • 9 tienen 1 dígito (1-9)
  • 90 tienen 2 dígitos (10-99)
  • 1 tiene 3 dígitos (100)

Dados números entre 1 y 1000.

  • 9 tienen 1 dígito
  • 90 tienen 2 dígitos
  • 900 tienen 3 dígitos
  • 1 tiene 4 dígitos

y así.

Entonces, si selecciona algunos al azar, entonces la gran mayoría de los números seleccionados tendrán el mismo número de dígitos, porque la gran mayoría de los valores posibles tienen el mismo número de dígitos.

Quentin
fuente
11
Su idea del significado de aleatoriedad distribuida perfecta y uniformemente es intrigante ...
19
@ R.Pate - la generación de números aleatorios no es de mucha utilidad a menos que se distribuya uniformemente a gran escala
annakata
3
Lea de nuevo. @David solo indica qué tipo de números hay entre los límites, no el resultado de seleccionar N números aleatorios. Admito que la titulación es engañosa.
nikc.org
3
Para que conste, voté a favor de esta respuesta y de @ jwoolard. Elegí esta como la respuesta aceptada porque los ejemplos dejan claro como el cristal por qué la distribución de números está sesgada a números con más dígitos.
Andrew Hedges
1
@ andrew-hedges tiene razón: esta es la respuesta más clara, pero gracias :)
jwoolard
56

Realmente se esperan sus resultados. Si los números aleatorios se distribuyen uniformemente en un rango de 1 a 10 ^ n, entonces esperaría que alrededor de 9/10 de los números tuvieran n dígitos y otros 9/100 tuvieran n-1 dígitos.

jwoolard
fuente
8
Exactamente. Se espera que la distribución del número de dígitos esté sesgada. Sin embargo, la distribución del logaritmo del número de dígitos debe ser uniforme.
Noldorin
45

Existen diferentes tipos de aleatoriedad. Math.random te da una distribución uniforme de números.

Si desea diferentes órdenes de magnitud, sugeriría usar una función exponencial para crear lo que se llama una distribución de ley de potencia :

function random_powerlaw(mini, maxi) {
    return Math.ceil(Math.exp(Math.random()*(Math.log(maxi)-Math.log(mini)))*mini)
}

Esta función debería proporcionarle aproximadamente la misma cantidad de números de 1 dígito que números de 2 dígitos y números de 3 dígitos.

También hay otras distribuciones para números aleatorios como la distribución normal (también llamada distribución gaussiana).

cristiano
fuente
Con este algoritmo, puse el minimum = 1y el maximum = 10y, a veces, obtendría 11 como resultado. Probablemente quisiste usar en Math.floorlugar deMath.round
Sam Eaton
1
¿Por qué funciona? ¿Transforma la distribución uniforme en distribución exponencial?
shinzou
@shinzou Pregunté en math.stackexchange y obtuve una fórmula ligeramente diferente como respuesta. Cambié el código para reflejar la fórmula derivada matemáticamente de math.stackexchange.
Christian
20

¡Me parece perfectamente aleatorio! (Sugerencia: depende del navegador).

Personalmente, creo que mi implementación sería mejor, aunque se la robé a XKCD , quien SIEMPRE debería ser reconocido:

function random() {
  return 4; // Chosen by a fair dice throw. Guaranteed to be random.
}
Arafangion
fuente
19
+1 por mencionar que depende del navegador, -1 por pedir prestado xkcd sin vincular.
Requerido o no, ya que es xkcd, se le atribuye. :)
Arafangion
2
OT: Estoy sorprendido y feliz de que "XKCD" fuera la respuesta a una pregunta del Reto Universitario esta semana: D
Matt Sach
2
Bergi: ¿Un enlace directo no es suficiente?
Arafangion
Creo que quieren decir que la broma no se citó correctamente ("random = 4;" en lugar de "return 4;")
Eren Tantekin
18

El siguiente artículo explica cómo math.random () en los principales navegadores web es (no) seguro: "Seguimiento temporal de usuarios en los principales navegadores y fugas y ataques de información entre dominios" por Amid Klein (2008) . No es más fuerte que las funciones PRNG integradas típicas de Java o Windows.

Por otro lado, implementar SFMT del período 2 ^ 19937-1 requiere 2496 bytes del estado interno mantenido para cada secuencia PRNG. Algunas personas pueden considerar esto como un costo imperdonable.

jj1bdx
fuente
1
+1: El artículo mencionado es genial, mucho más allá de lo que trataba la pregunta original.
Roland Illig
6

Si utiliza un número como 10000000000000000000, va más allá de la precisión del tipo de datos que utiliza Javascript. Tenga en cuenta que todos los números generados terminan en "00".

Greg
fuente
1
Sin embargo, ese no es su problema en este caso.
Joey
3
@Johannes - es uno de sus problemas :)
annakata
La distribución de IEE754 no es uniforme. Tal vez pueda representar de 0 a 999 en incrementos de dos y tener suficiente precisión para que note una distribución uniforme en ese rango si elige el número muchas veces. El 10% será de dos dígitos y el 90% de tres dígitos. Sin embargo, cuando empieces a alcanzar cifras realmente altas, el incremento superará 1. Es posible que solo puedas pasar de un billón de billones a un billón de billones de mil y no de un billón de billones uno. Aunque para números / escalas pequeñas, este efecto será insignificante o inexistente. Sin embargo, el efecto de escala tendrá un impacto mucho mayor.
jgmjgm
5

Probé el generador de números pseudoaleatorios JS en Chaos Game .

Mi triángulo de Sierpiński dice que es bastante aleatorio: Fractal

zie1ony
fuente
2
¿Le importaría compartir el código del triángulo aquí y jsfiddle / jsbin para que podamos comprobarlo fácilmente en la práctica para diferentes navegadores?
Fabrício Matté
1
Vale, pero dame unos días, porque necesito traducir el código al inglés. Ahora es polaco-inglés y tengo mucho trabajo.
zie1ony
1
@ zie1ony han pasado un par de días.
Trusktr
1
usp :( trabajo, trabajo, trabajo Enlace: kubaplas.vot.pl/green/fractal El primer parámetro es el número de vértice. El segundo es un punto de intersección (de 0 a 1) del segmento de línea. Simplemente experimente.
zie1ony
4
Enlace muerto, ¿tal vez un repositorio de Github en su lugar?
Mark K Cowan
3

Bueno, si está generando números hasta, digamos, 1e6, con suerte obtendrá todos los números con aproximadamente la misma probabilidad. Eso también significa que solo tienes una posibilidad entre diez de obtener un número con un dígito menos. Una probabilidad de uno en cien de obtener dos dígitos menos, etc. Dudo que veas mucha diferencia al usar otro RNG, porque tienes una distribución uniforme entre los números, no su logaritmo.

Joey
fuente
0

Los números no aleatorios distribuidos uniformemente de 1 a N tienen la misma propiedad. Tenga en cuenta que (en cierto sentido) es una cuestión de precisión. Una distribución uniforme de 0 a 99 (como números enteros) tiene el 90% de sus números con dos dígitos. Una distribución uniforme en 0-999999 tiene 905 de sus números con cinco dígitos.

Cualquier conjunto de números (bajo algunas condiciones no demasiado restrictivas) tiene una densidad. Cuando alguien quiera hablar de números "aleatorios", se debe especificar la densidad de estos números (como se indicó anteriormente). Una densidad común es la densidad uniforme. Hay otras: la densidad exponencial, la densidad normal, etc. Hay que elegir qué densidad es relevante antes de proponer un generador de números aleatorios. Además, los números que provienen de una densidad a menudo se pueden transformar fácilmente en otra densidad por medios cariados.

ttw
fuente