Comprender la “aleatoriedad”

No puedo entender esto, ¿qué es más aleatorio?

rand() 

O

 rand() * rand() 

Lo estoy encontrando un verdadero desafío para la mente, ¿podría ayudarme?

EDITAR:

Intuitivamente, sé que la respuesta matemática será que son igualmente aleatorios, pero no puedo evitar pensar que si “ejecutas el algoritmo de números aleatorios” dos veces al multiplicar los dos, crearás algo más aleatorio que solo hacer una vez

Solo una aclaración

Aunque las respuestas anteriores son correctas cada vez que intenta detectar la aleatoriedad de una variable pseudoaleatoria o su multiplicación, debe tener en cuenta que aunque Random () suele estar uniformemente distribuido, Random () * Random () no lo es.

Ejemplo

Esta es una muestra de distribución aleatoria uniforme simulada a través de una variable pseudoaleatoria:

Histograma de Aleatorio ()

  BarChart[BinCounts[RandomReal[{0, 1}, 50000], 0.01]] 

Si bien esta es la distribución que obtiene después de multiplicar dos variables aleatorias:

Histograma de Aleatorio () * Aleatorio ()

  BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] * RandomReal[{0, 1}, 50000], {50000}], 0.01]] 

Entonces, ambos son “aleatorios”, pero su distribución es muy diferente.

Otro ejemplo

Mientras que 2 * Random () se distribuye uniformemente:

Histograma de 2 * Aleatorio ()

  BarChart[BinCounts[2 * RandomReal[{0, 1}, 50000], 0.01]] 

Random () + Random () no lo es!

Histograma de Aleatorio () + Aleatorio ()

  BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] + RandomReal[{0, 1}, 50000], {50000}], 0.01]] 

El teorema del límite central

El teorema del límite central establece que la sum de Random () tiende a una distribución normal a medida que aumentan los términos.

Con solo cuatro términos, obtienes:

Histograma de Aleatorio () + Aleatorio () + Aleatorio () + Aleatorio ()

 BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] + RandomReal[{0, 1}, 50000] + Table[RandomReal[{0, 1}, 50000] + RandomReal[{0, 1}, 50000], {50000}], 0.01]] 

Y aquí puede ver el camino desde un uniforme hasta una distribución normal sumndo 1, 2, 4, 6, 10 y 20 variables aleatorias uniformemente distribuidas:

Histograma de diferentes números de variables aleatorias añadidas

Editar

Algunos créditos

Gracias a Thomas Ahle por señalar en los comentarios que las distribuciones de probabilidad que se muestran en las dos últimas imágenes se conocen como distribución Irwin-Hall.

Gracias a Heike por su maravillosa función rasgada []

Supongo que ambos métodos son tan aleatorios, aunque mi gutfeel diría que rand() * rand() es menos aleatorio porque generaría más ceros. Tan pronto como un rand() es 0 , el total se convierte en 0

Tampoco es “más aleatorio”.

rand() genera un conjunto predecible de números basado en una semilla psuedo-aleatoria (generalmente basada en la hora actual, que siempre está cambiando). Multiplicar dos números consecutivos en la secuencia genera una secuencia de números diferente, pero igualmente predecible.

Al abordar si esto reducirá las colisiones, la respuesta es no. Realmente boostá las colisiones debido al efecto de multiplicar dos números donde 0 < n < 1 . El resultado será una fracción más pequeña, causando un sesgo en el resultado hacia el extremo inferior del espectro.

Algunas explicaciones adicionales. En lo que sigue, "impredecible" y "aleatorio" se refieren a la capacidad de alguien para adivinar cuál será el siguiente número basado en números anteriores, es decir. un oracle

Given seed x que genera la siguiente lista de valores:

 0.3, 0.6, 0.2, 0.4, 0.8, 0.1, 0.7, 0.3, ... 

rand() generará la lista anterior, y rand() * rand() generará:

 0.18, 0.08, 0.08, 0.21, ... 

Ambos métodos siempre producirán la misma lista de números para la misma semilla, y por lo tanto son igualmente predecibles por un oracle. Pero si mira los resultados para multiplicar las dos llamadas, verá que todas están por debajo de 0.3 pesar de una distribución decente en la secuencia original. Los números son parciales debido al efecto de multiplicar dos fracciones. El número resultante siempre es más pequeño, por lo tanto, es mucho más probable que sea una colisión a pesar de ser igual de impredecible.

Simplificación excesiva para ilustrar un punto.

Suponga que su función aleatoria solo da como resultado 0 o 1 .

random() es uno de (0,1) , pero random()*random() es uno de (0,0,0,1)

Puede ver claramente que las posibilidades de obtener un 0 en el segundo caso no son en absoluto iguales a los de obtener un 1 .


Cuando publiqué esta respuesta por primera vez, quería mantenerla lo más breve posible para que la persona que la leyera entendiera de un vistazo la diferencia entre random() y random()*random() , pero no puedo evitar contestar la pregunta original del anuncio literario:

¿Cuál es más aleatorio?

Siendo ese random() , random()*random() , random()+random() , (random()+1)/2 o cualquier otra combinación que no conduzca a un resultado fijo tiene la misma fuente de entropía (o el mismo estado inicial en el caso de los generadores pseudoaleatorios), la respuesta sería que son igualmente aleatorios (la diferencia está en su distribución). Un ejemplo perfecto que podemos ver es el juego de Craps. El número que obtienes será random(1,6)+random(1,6) y todos sabemos que obtener 7 tiene la mayor probabilidad, pero eso no significa que el resultado de tirar dos dados sea más o menos aleatorio que el resultado de rodar uno.

Aquí hay una respuesta simple. Considera Monopoly. Lanzas dos dados de seis caras (o 2d6 para aquellos de ustedes que prefieren la notación de juego) y toman su sum. El resultado más común es 7 porque hay 6 formas posibles en las que puedes sacar un 7 (1,6 2,5 3,4 4,3 5,2 y 6,1). Mientras que un 2 solo se puede rodar en 1,1. Es fácil ver que rodar 2d6 es diferente a rodar 1d12, incluso si el rango es el mismo (ignorando que puedes obtener un 1 en 1d12, el punto sigue siendo el mismo). Multiplicar los resultados en lugar de agregarlos los sesgará de manera similar, y la mayoría de los resultados aparecerán en el medio del rango. Si intenta reducir los valores atípicos, este es un buen método, pero no ayudará a hacer una distribución pareja.

(Y por extraño que parezca, también boostá las tiradas bajas. Suponiendo que tu aleatoriedad comience en 0, verás un pico en 0 porque convertirá lo que la otra tirada en 0. Considera dos números aleatorios entre 0 y 1 (inclusive) ) y multiplicando. Si cualquiera de los resultados es un 0, todo se convierte en un 0 sin importar el otro resultado. La única forma de obtener un 1 es que ambos roles sean un 1. En la práctica, esto probablemente no importaría pero lo convierte en un gráfico extraño).

El obligatorio xkcd …
regreso 4; // elegido por fair dice roll, garantizado para ser al azar.

Puede ayudar pensar en esto en números más discretos. Considere querer generar números aleatorios entre 1 y 36, por lo que decide que la forma más fácil es tirar dos dados de 6 caras. Obtienes esto:

  1 2 3 4 5 6 ----------------------------- 1| 1 2 3 4 5 6 2| 2 4 6 8 10 12 3| 3 6 9 12 15 18 4| 4 8 12 16 20 24 5| 5 10 15 20 25 30 6| 6 12 18 24 30 36 

Entonces tenemos 36 números, pero no todos están representados de manera justa, y algunos no aparecen en absoluto. Los números cerca de la diagonal central (esquina inferior izquierda a esquina superior derecha) ocurrirán con la frecuencia más alta.

Los mismos principios que describen la distribución injusta entre los dados se aplican igualmente a los números de punto flotante entre 0.0 y 1.0.

Algunas cosas sobre “aleatoriedad” son contraintuitivas.

Suponiendo una distribución plana de rand() , lo siguiente le proporcionará distribuciones no planas:

  • alto sesgo: sqrt(rand(range^2))
  • sesgo que alcanza su punto máximo en el medio: (rand(range) + rand(range))/2
  • low: bias: range - sqrt(rand(range^2))

Hay muchas otras maneras de crear curvas de sesgo específicas. Hice una prueba rápida de rand() * rand() y obtiene una distribución muy no lineal.

“aleatorio” vs. “más aleatorio” es un poco como preguntar qué Zero es más cero.

En este caso, rand es un PRNG, por lo que no es totalmente aleatorio. (de hecho, bastante predecible si se conoce la semilla). Multiplicarlo por otro valor lo hace no más o menos aleatorio.

Un verdadero RNG criptográfico será aleatorio. Y ejecutar valores a través de cualquier tipo de función no puede agregarle más entropía, y es muy probable que elimine la entropía, haciendo que no sea más aleatoria.

La mayoría de las implementaciones de rand () tienen algún período. Es decir, después de una enorme cantidad de llamadas, la secuencia se repite. La secuencia de salidas de rand() * rand() repite en la mitad del tiempo, por lo que es “menos aleatorio” en ese sentido.

Además, sin una construcción cuidadosa, la realización de la aritmética en valores aleatorios tiende a causar menos aleatoriedad. Un cartel arriba citado ” rand() + rand() + rand() …” (k veces, digamos) que de hecho tenderá a k multiplicado por el valor promedio del rango de valores rand() regresa. (Es una caminata aleatoria con pasos simétricos sobre eso).

Supongamos que su función rand () devuelve un número real aleatorio distribuido uniformemente en el rango [0,1). (Sí, este ejemplo permite una precisión infinita. Esto no cambiará el resultado). No seleccionó un idioma en particular y diferentes idiomas pueden hacer cosas diferentes, pero el siguiente análisis se mantiene con modificaciones para cualquier implementación no perversa de rand ( ) El producto rand() * rand() también está en el rango [0,1) pero ya no se distribuye uniformemente. De hecho, es probable que el producto esté en el intervalo [0,1 / 4) como en el intervalo [1 / 4,1). Más multiplicaciones sesgarán el resultado aún más hacia cero. Esto hace que el resultado sea más predecible. A grandes rasgos, más predecible == menos aleatorio.

Prácticamente cualquier secuencia de operaciones con entradas uniformemente aleatorias será no uniformemente aleatoria, lo que conducirá a una mayor previsibilidad. Con cuidado, uno puede superar esta propiedad, pero habría sido más fácil generar un número aleatorio distribuido uniformemente en el rango que realmente quería en lugar de perder el tiempo con la aritmética.

El concepto que está buscando es “entropía”, el “grado” de desorden de una cadena de bits. La idea es más fácil de entender en términos del concepto de “máxima entropía”.

Una definición aproximada de una cadena de bits con máxima entropía es que no se puede express exactamente en términos de una cadena de bits más corta (es decir, usando algún algoritmo para expandir la cadena más pequeña a la cadena original).

La relevancia de la entropía máxima para la aleatoriedad se deriva del hecho de que si eliges un número “al azar”, casi con seguridad eliges un número cuya cadena de bits está cerca de tener máxima entropía, es decir, no puede ser comprimida. Esta es nuestra mejor comprensión de lo que caracteriza a un número “aleatorio”.

Entonces, si quiere hacer un número aleatorio de dos muestras aleatorias que son “dos veces” como al azar, concatenaría las dos cadenas de bits juntas. Prácticamente, simplemente rellenas las muestras en las mitades alta y baja de una palabra de longitud doble.

En una nota más práctica, si te sientes agobiado por un rand rabioso (), a veces puede ayudar tener un par de muestras juntas — aunque, si está realmente roto, incluso ese procedimiento no ayudará.

La respuesta aceptada es bastante encantadora, pero hay otra manera de responder a su pregunta. La respuesta de PachydermPuncher ya tiene este enfoque alternativo, y voy a expandirlo un poco.

La forma más fácil de pensar acerca de la teoría de la información es en términos de la unidad de información más pequeña, un solo bit.

En la biblioteca estándar de C, rand() devuelve un entero en el rango de 0 a RAND_MAX , un límite que puede definirse de manera diferente según la plataforma. Supongamos que RAND_MAX pasa a definirse como 2^n - 1 donde n es un entero (este es el caso en la implementación de Microsoft, donde n es 15). Entonces diríamos que una buena implementación devolvería n bits de información.

Imagine que rand() construye números aleatorios al lanzar una moneda para encontrar el valor de un bit, y luego repetir hasta que tenga un lote de 15 bits. Entonces los bits son independientes (el valor de cualquier bit no influye en la probabilidad de que otros bits en el mismo lote tengan un cierto valor). Por lo tanto, cada bit considerado independientemente es como un número aleatorio entre 0 y 1 inclusive, y está “distribuido uniformemente” sobre ese rango (lo más probable es que sea 0 como 1).

La independencia de los bits asegura que los números representados por lotes de bits también se distribuirán uniformemente en su rango. Esto es intuitivamente obvio: si hay 15 bits, el rango permitido es cero a 2^15 - 1 = 32767. Cada número en ese rango es un patrón único de bits, como por ejemplo:

 010110101110010 

y si los bits son independientes, entonces no es más probable que ocurra un patrón que cualquier otro patrón. Entonces todos los números posibles en el rango son igualmente probables. Y así ocurre lo contrario: si rand() produce números enteros distribuidos uniformemente, esos números están hechos de bits independientes.

Así que piense en rand() como una línea de producción para hacer bits, que simplemente les sirve en lotes de tamaño arbitrario. Si no le gusta el tamaño, divida los lotes en partes individuales y luego vuélvalos a juntar en las cantidades que desee (aunque si necesita un rango particular que no sea una potencia de 2, necesita reducir sus números). , y de lejos la forma más fácil de hacerlo es convertir a punto flotante).

Volviendo a su sugerencia original, suponga que desea pasar de lotes de 15 a lotes de 30, solicite rand() para el primer número, desplace el cambio por 15 lugares y luego agregue otro rand() a él. Esa es una forma de combinar dos llamadas a rand() sin perturbar una distribución uniforme. Funciona simplemente porque no hay superposición entre las ubicaciones donde coloca los bits de información.

Esto es muy diferente a “estirar” el rango de rand() al multiplicar por una constante. Por ejemplo, si quieres duplicar el rango de rand() puedes multiplicar por dos, ¡pero ahora solo obtendrías números pares y nunca impares! Esa no es exactamente una distribución fluida y podría ser un problema serio dependiendo de la aplicación, por ejemplo, un juego parecido a la ruleta que supuestamente permite apuestas impares / pares. (Al pensar en términos de bits, evitarías ese error intuitivamente, porque te darías cuenta de que multiplicar por dos es lo mismo que cambiar los bits a la izquierda (mayor importancia) por un lugar y llenar el vacío con cero. Entonces, obviamente, la cantidad de información es la misma, simplemente se movió un poco).

Tales espacios en rangos de números no pueden ser discutidos en aplicaciones de números de coma flotante, porque los rangos de coma flotante tienen inherentes brechas que simplemente no se pueden representar en absoluto: existe un número infinito de números reales que faltan en el espacio entre cada dos flotantes representables números de puntos! Entonces, tenemos que aprender a vivir con las lagunas de todos modos.

Como otros han advertido, la intuición es arriesgada en esta área, especialmente porque los matemáticos no pueden resistir el atractivo de los números reales, que son cosas terriblemente confusas llenas de infinidades retorcidas y aparentes paradojas.

Pero al menos si lo piensas en términos de bits, tu intuición podría llevarte un poco más allá. Los bits son realmente fáciles, incluso las computadoras pueden entenderlos.

Como otros han dicho, la respuesta fácil y sencilla es: No, no es más aleatorio, pero sí cambia la distribución.

Supongamos que estás jugando un juego de dados. Tienes algunos dados completamente justos y aleatorios. ¿Las tiradas de la tirada serían “más aleatorias” si antes de cada tirada de dado, primero pusiste dos dados en un cuenco, lo sacudiste, escogiste uno de los dados al azar y luego lo hiciste girar? Claramente, no haría ninguna diferencia. Si ambos dados dan números aleatorios, elegir al azar uno de los dos dados no hará ninguna diferencia. De cualquier forma, obtendrá un número aleatorio entre 1 y 6 con distribución equitativa en una cantidad suficiente de tiradas.

Supongo que en la vida real tal procedimiento podría ser útil si sospechas que los dados NO son justos. Si, por ejemplo, los dados están ligeramente desequilibrados por lo que uno tiende a dar 1 más a menudo que 1/6 del tiempo, y otro tiende a dar 6 inusualmente, entonces elegir al azar entre los dos tenderá a oscurecer el sesgo. (Aunque en este caso, 1 y 6 aún aparecerían más de 2, 3, 4 y 5. Bueno, supongo que depende de la naturaleza del desequilibrio).

Hay muchas definiciones de aleatoriedad. Una definición de una serie aleatoria es que se trata de una serie de números producidos por un proceso aleatorio. Según esta definición, si lanzo un dado justo 5 veces y obtengo los números 2, 4, 3, 2, 5, eso es una serie aleatoria. Si doy la vuelta a esa misma muerta 5 veces más y obtengo 1, 1, 1, 1, 1, entonces esa también es una serie aleatoria.

Varios carteles han señalado que las funciones aleatorias en una computadora no son realmente aleatorias sino más bien pseudoaleatorias, y que si conoce el algoritmo y la semilla son completamente predecibles. Esto es cierto, pero la mayoría de las veces completamente irrelevante. Si mezclo una baraja de cartas y luego las vuelvo una a la vez, esta debería ser una serie aleatoria. Si alguien echa un vistazo a las cartas, el resultado será completamente predecible, pero según la mayoría de las definiciones de aleatoriedad, esto no lo hará menos aleatorio. Si la serie pasa pruebas estadísticas de aleatoriedad, el hecho de que eche un vistazo a las cartas no cambiará ese hecho. En la práctica, si estamos jugando grandes sums de dinero en su capacidad para adivinar la próxima carta, entonces el hecho de que eche un vistazo a las cartas es muy relevante. Si estamos utilizando la serie para simular las selecciones del menú de los visitantes de nuestro sitio web con el fin de probar el rendimiento del sistema, entonces el hecho de que echó un vistazo no hará ninguna diferencia. (Siempre y cuando no modifique el progtwig para aprovechar este conocimiento).

EDITAR

No creo que pueda responder mi pregunta sobre el problema de Monty Hall en un comentario, así que actualizaré mi respuesta.

Para aquellos que no leyeron el enlace de Belisarius, la esencia de esto es: un concursante de un juego tiene una opción de 3 puertas. Detrás de uno hay un premio valioso, detrás de los otros algo inútil. Él toma la puerta n. ° 1. Antes de revelar si es un ganador o un perdedor, el anfitrión abre la puerta n. ° 3 para revelar que es un perdedor. Luego le da al concursante la oportunidad de cambiar a la puerta n. ° 2. ¿Debería el concursante hacer esto o no?

La respuesta, que ofende la intuición de muchas personas, es que debe cambiar. La probabilidad de que su elección original sea la ganadora es 1/3, que la otra puerta es la ganadora es 2/3. Mi intuición inicial, junto con la de muchas otras personas, es que no habría ganancia en el cambio, que las probabilidades se han cambiado a 50:50.

Después de todo, supongamos que alguien encendió el televisor justo después de que el anfitrión abriera la puerta que se estaba perdiendo. Esa persona vería dos puertas cerradas restantes. Suponiendo que conozca la naturaleza del juego, diría que hay una posibilidad 1/2 de que cada puerta esconda el premio. ¿Cómo pueden las probabilidades para el espectador ser 1/2: 1/2, mientras que las probabilidades para el concursante son 1/3: 2/3?

Realmente tenía que pensar en esto para mejorar mi intuición. Para entenderlo, comprenda que cuando hablamos de probabilidades en un problema como este, nos referimos a la probabilidad que asigna dada la información disponible. Para un miembro de la tripulación que dejó el premio, digamos, la puerta n. ° 1, la probabilidad de que el premio esté detrás de la puerta n. ° 1 es del 100% y la probabilidad de que esté detrás de cualquiera de las otras dos puertas es cero.

Las probabilidades del miembro de la tripulación son diferentes de las probabilidades del concursante porque él sabe algo que el concursante no sabe, es decir, a qué puerta dejó el premio. Del mismo modo, las probabilidades del contendiente son diferentes de las probabilidades del espectador porque él sabe algo que el espectador no sabe, es decir, qué puerta eligió inicialmente. Esto no es irrelevante, porque la elección del anfitrión de qué puerta abrir no es aleatoria. No abrirá la puerta que eligió el concursante, y no abrirá la puerta que oculta el premio. Si estas son la misma puerta, eso le deja dos opciones. Si son puertas diferentes, eso deja solo a uno.

Entonces, ¿cómo se nos ocurre 1/3 y 2/3? Cuando el concursante escogió originalmente una puerta, tenía una posibilidad de 1/3 de elegir al ganador. Creo que eso es obvio. Eso significa que había una posibilidad de 2/3 de que una de las otras puertas sea la ganadora. If the host game him the opportunity to switch without giving any additional information, there would be no gain. Again, this should be obvious. But one way to look at it is to say that there is a 2/3 chance that he would win by switching. But he has 2 alternatives. So each one has only 2/3 divided by 2 = 1/3 chance of being the winner, which is no better than his original pick. Of course we already knew the final result, this just calculates it a different way.

But now the host reveals that one of those two choices is not the winner. So of the 2/3 chance that a door he didn’t pick is the winner, he now knows that 1 of the 2 alternatives isn’t it. The other might or might not be. So he no longer has 2/3 dividied by 2. He has zero for the open door and 2/3 for the closed door.

Consider you have a simple coin flip problem where even is considered heads and odd is considered tails. The logical implementation is:

 rand() mod 2 

Over a large enough distribution, the number of even numbers should equal the number of odd numbers.

Now consider a slight tweak:

 rand() * rand() mod 2 

If one of the results is even, then the entire result should be even. Consider the 4 possible outcomes (even * even = even, even * odd = even, odd * even = even, odd * odd = odd). Now, over a large enough distribution, the answer should be even 75% of the time.

I’d bet heads if I were you.

This comment is really more of an explanation of why you shouldn’t implement a custom random function based on your method than a discussion on the mathematical properties of randomness.

When in doubt about what will happen to the combinations of your random numbers, you can use the lessons you learned in statistical theory.

In OP’s situation he wants to know what’s the outcome of X*X = X^2 where X is a random variable distributed along Uniform[0,1]. We’ll use the CDF technique since it’s just a one-to-one mapping.

Since X ~ Uniform[0,1] it’s cdf is: f X (x) = 1 We want the transformation Y <- X^2 thus y = x^2 Find the inverse x(y): sqrt(y) = x this gives us x as a function of y. Next, find the derivative dx/dy: d/dy (sqrt(y)) = 1/(2 sqrt(y))

The distribution of Y is given as: f Y (y) = f X (x(y)) |dx/dy| = 1/(2 sqrt(y))

We’re not done yet, we have to get the domain of Y. since 0 <= x < 1, 0 <= x^2 < 1 so Y is in the range [0, 1). If you wanna check if the pdf of Y is indeed a pdf, integrate it over the domain: Integrate 1/(2 sqrt(y)) from 0 to 1 and indeed, it pops up as 1. Also, notice the shape of the said function looks like what belisarious posted.

As for things like X 1 + X 2 + … + X n , (where X i ~ Uniform[0,1]) we can just appeal to the Central Limit Theorem which works for any distribution whose moments exist. This is why the Z-test exists actually.

Other techniques for determining the resulting pdf include the Jacobian transformation (which is the generalized version of the cdf technique) and MGF technique.

EDIT: As a clarification, do note that I’m talking about the distribution of the resulting transformation and not its randomness . That’s actually for a separate discussion. Also what I actually derived was for (rand())^2. For rand() * rand() it’s much more complicated, which, in any case won’t result in a uniform distribution of any sorts.

It’s not exactly obvious, but rand() is typically more random than rand()*rand() . What’s important is that this isn’t actually very important for most uses.

But firstly, they produce different distributions. This is not a problem if that is what you want, but it does matter. If you need a particular distribution, then ignore the whole “which is more random” question. So why is rand() more random?

The core of why rand() is more random (under the assumption that it is producing floating-point random numbers with the range [0..1], which is very common) is that when you multiply two FP numbers together with lots of information in the mantissa, you get some loss of information off the end; there’s just not enough bit in an IEEE double-precision float to hold all the information that was in two IEEE double-precision floats uniformly randomly selected from [0..1], and those extra bits of information are lost. Of course, it doesn’t matter that much since you (probably) weren’t going to use that information, but the loss is real. It also doesn’t really matter which distribution you produce (ie, which operation you use to do the combination). Each of those random numbers has (at best) 52 bits of random information – that’s how much an IEEE double can hold – and if you combine two or more into one, you’re still limited to having at most 52 bits of random information.

Most uses of random numbers don’t use even close to as much randomness as is actually available in the random source. Get a good PRNG and don’t worry too much about it. (The level of “goodness” depends on what you’re doing with it; you have to be careful when doing Monte Carlo simulation or cryptography, but otherwise you can probably use the standard PRNG as that’s usually much quicker.)

Floating randoms are based, in general, on an algorithm that produces an integer between zero and a certain range. As such, by using rand()*rand(), you are essentially saying int_rand()*int_rand()/rand_max^2 – meaning you are excluding any prime number / rand_max^2.

That changes the randomized distribution significantly.

rand() is uniformly distributed on most systems, and difficult to predict if properly seeded. Use that unless you have a particular reason to do math on it (ie, shaping the distribution to a needed curve).

Multiplying numbers would end up in a smaller solution range depending on your computer architecture.

If the display of your computer shows 16 digits rand() would be say 0.1234567890123 multiplied by a second rand() , 0.1234567890123, would give 0.0152415 something you’d definitely find fewer solutions if you’d repeat the experiment 10^14 times.

Most of these distributions happen because you have to limit or normalize the random number.

We normalize it to be all positive, fit within a range, and even to fit within the constraints of the memory size for the assigned variable type.

In other words, because we have to limit the random call between 0 and X (X being the size limit of our variable) we will have a group of “random” numbers between 0 and X.

Now when you add the random number to another random number the sum will be somewhere between 0 and 2X…this skews the values away from the edge points (the probability of adding two small numbers together and two big numbers together is very small when you have two random numbers over a large range).

Think of the case where you had a number that is close to zero and you add it with another random number it will certainly get bigger and away from 0 (this will be true of large numbers as well as it is unlikely to have two large numbers (numbers close to X) returned by the Random function twice.

Now if you were to setup the random method with negative numbers and positive numbers (spanning equally across the zero axis) this would no longer be the case.

Say for instance RandomReal({-x, x}, 50000, .01) then you would get an even distribution of numbers on the negative a positive side and if you were to add the random numbers together they would maintain their “randomness”.

Now I’m not sure what would happen with the Random() * Random() with the negative to positive span…that would be an interesting graph to see…but I have to get back to writing code now. :-PAG

  1. There is no such thing as more random. It is either random or not. Random means “hard to predict”. It does not mean non-deterministic. Both random() and random() * random() are equally random if random() is random. Distribution is irrelevant as far as randomness goes. If a non-uniform distribution occurs, it just means that some values are more likely than others; they are still unpredictable.

  2. Since pseudo-randomness is involved, the numbers are very much deterministic. However, pseudo-randomness is often sufficient in probability models and simulations. It is pretty well known that making a pseudo-random number generator complicated only makes it difficult to analyze. It is unlikely to improve randomness; it often causes it to fail statistical tests.

  3. The desired properties of the random numbers are important: repeatability and reproducibility, statistical randomness, (usually) uniformly distributed, and a large period are a few.

  4. Concerning transformations on random numbers: As someone said, the sum of two or more uniformly distributed results in a normal distribution. This is the additive central limit theorem. It applies regardless of the source distribution as long as all distributions are independent and identical. The multiplicative central limit theorem says the product of two or more independent and indentically distributed random variables is lognormal. The graph someone else created looks exponential, but it is really lognormal. So random() * random() is lognormally distributed (although it may not be independent since numbers are pulled from the same stream). This may be desirable in some applications. However, it is usually better to generate one random number and transform it to a lognormally-distributed number. Random() * random() may be difficult to analyze.

For more information, consult my book at http://www.performotwig.org. The book is under construction, but the relevant material is there. Note that chapter and section numbers may change over time. Chapter 8 (probability theory) — sections 8.3.1 and 8.3.3, chapter 10 (random numbers).

We can compare two arrays of numbers regarding the randomness by using Kolmogorov complexity If the sequence of numbers can not be compressed, then it is the most random we can reach at this length… I know that this type of measurement is more a theoretical option…

Actually, when you think about it rand() * rand() is less random than rand() . Este es el por qué.

Essentially, there are the same number of odd numbers as even numbers. And saying that 0.04325 is odd, and like 0.388 is even, and 0.4 is even, and 0.15 is odd,

That means that rand() has a equal chance of being an even or odd decimal .

On the other hand, rand() * rand() has it’s odds stacked a bit differently. Lets say:

 double a = rand(); double b = rand(); double c = a * b; 

a and b both have a 50% precent chance of being even or odd. Knowing that

  • even * even = even
  • even * odd = even
  • odd * odd = odd
  • odd * even = even

means that there a 75% chance that c is even, while only a 25% chance it’s odd, making the value of rand() * rand() more predictable than rand() , therefore less random.

Use a linear feedback shift register (LFSR) that implements a primitive polynomial.

The result will be a sequence of 2^n pseudo-random numbers, ie none repeating in the sequence where n is the number of bits in the LFSR …. resulting in a uniform distribution.

http://en.wikipedia.org/wiki/Linear_feedback_shift_register http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf

Use a “random” seed based on microsecs of your computer clock or maybe a subset of the md5 result on some continuously changing data in your file system.

For example, a 32-bit LFSR will generate 2^32 unique numbers in sequence (no 2 alike) starting with a given seed. The sequence will always be in the same order, but the starting point will be different (obviously) for a different seeds. So, if a possibly repeating sequence between seedings is not a problem, this might be a good choice.

I’ve used 128-bit LFSR’s to generate random tests in hardware simulators using a seed which is the md5 results on continuously changing system data.

Assuming that rand() returns a number between [0, 1) it is obvious that rand() * rand() will be biased toward 0. This is because multiplying x by a number between [0, 1) will result in a number smaller than x . Here is the distribution of 10000 more random numbers:

 google.charts.load("current", { packages: ["corechart"] }); google.charts.setOnLoadCallback(drawChart); function drawChart() { var i; var randomNumbers = []; for (i = 0; i < 10000; i++) { randomNumbers.push(Math.random() * Math.random()); } var chart = new google.visualization.Histogram(document.getElementById("chart-1")); var data = new google.visualization.DataTable(); data.addColumn("number", "Value"); randomNumbers.forEach(function(randomNumber) { data.addRow([randomNumber]); }); chart.draw(data, { title: randomNumbers.length + " rand() * rand() values between [0, 1)", legend: { position: "none" } }); } 
  
Generating chart...

OK, so I will try to add some value to complement others answers by saying that you are creating and using a random number generator.

Random number generators are devices (in a very general sense) that have multiple characteristics which can be modified to fit a purpose. Some of them (from me) are:

  • Entropy: as in Shannon Entropy
  • Distribution: statistical distribution (poisson, normal, etc.)
  • Type: what is the source of the numbers (algorithm, natural event, combination of, etc.) and algorithm applied.
  • Efficiency: rapidity or complexity of execution.
  • Patterns: periodicity, sequences, runs, etc.
  • and probably more…

In most answers here, distribution is the main point of interest, but by mix and matching functions and parameters, you create new ways of generating random numbers which will have different characteristics for some of which the evaluation may not be obvious at first glance.

It’s easy to show that the sum of the two random numbers is not necessarily random. Imagine you have a 6 sided die and roll. Each number has a 1/6 chance of appearing. Now say you had 2 dice and summed the result. The distribution of those sums is not 1/12. ¿Por qué? Because certain numbers appear more than others. There are multiple partitions of them. For example the number 2 is the sum of 1+1 only but 7 can be formed by 3+4 or 4+3 or 5+2 etc… so it has a larger chance of coming up.

Therefore, applying a transform, in this case addition on a random function does not make it more random, or necessarily preserve randomness. In the case of the dice above, the distribution is skewed to 7 and therefore less random.

As others already pointed out, this question is hard to answer since everyone of us has his own picture of randomness in his head.

That is why, I would highly recommend you to take some time and read through this site to get a better idea of randomness:

To get back to the real question. There is no more or less random in this term:

both only appears random !

In both cases – just rand() or rand() * rand() – the situation is the same: After a few billion of numbers the sequence will repeat(!) . It appears random to the observer, because he does not know the whole sequence, but the computer has no true random source – so he can not produce randomness either.

eg: Is the weather random? We do not have enough sensors or knowledge to determine if weather is random or not.

The answer would be it depends, hopefully the rand()*rand() would be more random than rand(), but as:

  • both answers depends on the bit size of your value
  • that in most of the cases you generate depending on a pseudo-random algorithm (which is mostly a number generator that depends on your computer clock, and not that much random).
  • make your code more readable (and not invoke some random voodoo god of random with this kind of mantra).

Well, if you check any of these above I suggest you go for the simple “rand()”. Because your code would be more readable (wouldn’t ask yourself why you did write this, for …well… more than 2 sec), easy to maintain (if you want to replace you rand function with a super_rand).

If you want a better random, I would recommend you to stream it from any source that provide enough noise ( radio static ), and then a simple rand() should be enough.