Búsqueda de sitios web

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


Durante 6 años he tenido una página de generador 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 docenas, si no cientos, de concursos y sorteos en foros de discusión y blogs (lo sé porque veo los referidos en mis registros web y generalmente voy 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 encontró 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 era de solo unas 2 órdenes de magnitud.

¿Por qué?

Aquí está la versión con bucle, para que la pruebes por ti mismo:

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

Incluye tanto una implementación sencilla tomada de la Red de Desarrolladores de Mozilla como algo de código de 1997 que tomé de una página web que ya no existe ("Central Randomizer 1.3" de Paul Houle). Mira el código 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 incorporada de JavaScript Math.random. ¡Gracias!

Respuesta #1

Dado números entre 1 y 100.

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

Dados números entre 1 y 1000.

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

y así sucesivamente.

Entonces, si seleccionas algunos al azar, 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.

Respuesta #2

Tus resultados son en realidad esperados. Si los números aleatorios están distribuidos uniformemente en un rango de 1 a 10^n, entonces se esperaría que aproximadamente 9/10 de los números tengan n dígitos, y un 9/100 adicional tenga n-1 dígitos.

Respuesta #3

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

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

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

Esta función debería darte aproximadamente el mismo número de números de 1 dígito que de números de 2 dígitos y de números de 3 dígitos.

También existen otras distribuciones para números aleatorios, como la distribución normal (también llamada distribución Gaussiana).

Respuesta #4

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

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

function random() {
  return 4; // Chosen by a fair dice throw. Guaranteed to be random.
}

Respuesta #5

El siguiente artículo explica cómo math.random() en los principales navegadores web es (in)seguro: "Seguimiento temporal de usuarios en los principales navegadores y fuga de información y ataques 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 de PRNG. Algunas personas pueden considerar esto un costo imperdonable.

Artículos relacionados