¿Por qué C++ rand() parece generar solo números del mismo orden de magnitud?


En una pequeña aplicación escrita en C / C++, me enfrento a un problema con la función rand y tal vez la semilla:

Quiero producir una secuencia de números aleatorios que son de diferentes órdenes, es decir, con diferentes valores de logaritmo (base 2). Pero parece que todos los números producidos son del mismo orden, fluctuando entre 2^25 y 2^30.

¿Se debe a que rand() está sembrado con tiempo Unix que ahora es un número relativamente grande? ¿Qué estoy olvidando ? Yo he sembrado rand() solo una vez al comienzo del main().

 146
Author: templatetypedef, 2013-06-20

9 answers

No son sólo el 3% de los números entre 1 y 230 que NO entre 225 y 230. Por lo tanto, esto suena bastante normal:)

Porque 225 / 230 = 2-5 = 1/32 = 0.03125 = 3.125%

 476
Author: C4stor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-24 07:44:25

El verde claro es la región entre 0 y 225; el verde oscuro es la región entre 225 y 230. Las garrapatas son potencias de 2.

distribución

 272
Author: Casey Chu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-21 00:57:01

Necesita ser más preciso: desea diferentes valores de logaritmo base 2, pero ¿qué distribución desea para esto? Las funciones rand () estándar generan una distribución uniforme, necesitará transformar esta salida usando la función cuantil asociada con la distribución que desea.

Si nos dice la distribución, entonces podemos decirle la función quantile que necesita.

 42
Author: Bathsheba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-20 09:29:23

Si quieres diferentes órdenes de magnitud, ¿por qué no simplemente probar pow(2, rand())? O tal vez elegir el orden directamente como rand(), como Harold sugirió?

 18
Author: aspiring_sarge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-20 14:39:38

@C4stor hizo un gran comentario. Pero, para un caso más general y más fácil de entender para humanos (base 10): para el rango de 1 a 10^n, ~90% de los números son de 10^(n-1) a 10^n, por lo tanto, ~99% de los números van de 10^(n-2) a 10^n. Siga agregando tantos decimales como desee.

Matemáticas divertidas, si sigues haciendo esto para n, puedes ver que de 1 a 10^n, 99.9999...% = 100% de los números son de 10^0 a 10^n con este método.

Ahora sobre el código, si si desea un número aleatorio con órdenes aleatorios de magnitud, de 0 a 10^n, puede hacer:

  1. Generar un pequeño número aleatorio de 0 a n

  2. Si conoce el rango que tiene n, genere un gran número aleatorio de orden 10^k donde k > max{n}.

  3. Corte el número aleatorio más largo para obtener los n dígitos de este gran número aleatorio.

 13
Author: Francisco Presencia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-21 14:58:44

La respuesta básica (y correcta) ya fue dada y aceptada arriba: hay 10 números entre 0 y 9, 90 números entre 10 y 99, 900 entre 100 y 999, etc.

Para una forma computacionalmente eficiente de obtener una distribución con aproximadamente distribución logarítmica, desea cambiar a la derecha su número aleatorio por un número aleatorio:

s = rand() & 31; // a random number between 0 and 31 inclusive, assuming RAND_MAX = 2^32-1
r = rand() >> s; // right shift

No es perfecto, pero es mucho más rápido que la computación pow(2, rand()*scalefactor). Será "lumpy" en el sentido de que la distribución será ser uniforme para números dentro de un factor 2 (uniforme para 128 a 255, la mitad de la densidad para 256 a 1023, etc.).

Aquí hay un histograma de la frecuencia de los números 0 a 31 (en muestras de 1M):

introduzca la descripción de la imagen aquí

 13
Author: Floris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-25 19:21:14

Hay exactamente igual número de números entre 0 y 2^29 y 2^29 y 2^30.

Otra forma de ver el problema: considere la representación binaria del número aleatorio que genera, la probabilidad de que el bit más alto sea 1 es igual a 1/2, y, por lo tanto, obtiene el orden 29 en la mitad de los casos. Lo que quieres es ver un número que estaría por debajo de 2^25, pero eso significa que 5 bits más altos son todos cero, lo que sucede con una baja probabilidad de 1/32. Lo más probable es que incluso si se ejecuta para un mucho tiempo nunca verás el orden por debajo de 15 en absoluto (la probabilidad es algo así como rodar 6 6 veces seguidas).

Ahora, la parte de tu pregunta sobre la semilla. No, la semilla no puede determinar el rango desde el que se generan los números, solo determina el primer elemento inicial. Piense en rand () como una secuencia de todos los números posibles en el rango (permutación predeterminada). La semilla determina dónde comienza a dibujar números de la secuencia. Es por eso que si quieres (pseudo) aleatoriedad, usas el tiempo actual para inicializar la secuencia: no te importa que la posición desde la que comienzas no esté distribuida uniformemente, todo lo que importa es que nunca comiences desde la misma posición.

 5
Author: Vadim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-21 00:31:47

Uso pow(2,rand()) ¡dará las respuestas en orden de magnitud deseada!!

 2
Author: Shivendra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-22 17:40:31

Si desea usar números aleatorios de un servicio en línea, puede usar wget para eso, es posible que desee ver también puede utilizar servicios como random.org para su generación de números aleatorios, puede atraparlos usando wget y luego leer los números del archivo descargado

wget -q https://www.random.org/integers/?num=100&min=1&max=100&col=5&base=10&format=html&rnd=new -O new.txt

Http://programmingconsole.blogspot.in/2013/11/a-better-and-different-way-to-generate.html

 2
Author: Namit Sinha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-24 07:45:53