¿Por qué obtengo este patrón de color particular cuando uso rand()?


Intenté crear un archivo bmp, así:

 uint8_t raw_r[pixel_width][pixel_height];
 uint8_t raw_g[pixel_width][pixel_height];
 uint8_t raw_b[pixel_width][pixel_height];
 uint8_t blue(uint32_t x, uint32_t y)
 {
     return (rand()%2)? (x+y)%rand() : ((x*y%1024)%rand())%2 ? (x-y)%rand() : rand();
 }
 uint8_t green(uint32_t x, uint32_t y)
 {
     return (rand()%2)? (x-y)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
 }
 uint8_t red(uint32_t x, uint32_t y)
 {
     return (rand()%2)? (y-x)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
 }

 for (y=0; y<pixel_height; ++y)
 {
     for (x=0; x<pixel_width; ++x)
     {
         raw_b[x][y]=blue(x, y);
         raw_g[x][y]=green(x, y);
         raw_r[x][y]=red(x, y);
     }
 }

Esperaba obtener algo al azar (ruido blanco). Sin embargo, la salida es interesante:

introduzca la descripción de la imagen aquí

¿Sabes la razón del por qué?


Ahora, está claro que no tiene nada que ver con rand(). Prueba también este código:

for (x=0; x<pixel_width; ++x)
         for (y=0; y<pixel_height; ++y)
         {
             r[x][y] = (x+y);
             g[x][y] = (y-x);
             /* b[x][y] = rand()%2? x : y; */
         }

introduzca la descripción de la imagen aquí

 154
Author: Arnav Borborah, 2018-09-22

2 answers

Inicialmente iba a tener la misma respuesta que todos los demás y atribuirlo a los problemas con rand(). Sin embargo, pensé mejor en hacerlo y en su lugar analizó la distribución que sus matemáticas están produciendo realmente.

TL;DR: El patrón que ves no tiene nada que ver con el generador de números aleatorios subyacente y en su lugar se debe simplemente a la forma en que tu programa está manipulando los números.

Me apegaré a su función azul ya que son todos similar.

uint8_t blue(uint32_t x, uint32_t y) {
    return (rand() % 2)                  ? (x + y) % rand() :
           ((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
                                           rand();
}

Cada valor de píxel se selecciona de una de las tres funciones: (x + y) % rand(), (x - y) % rand(), y rand();

Veamos las imágenes producidas por cada uno de ellos solo.

  • rand()

Esto es lo que esperarías, solo ruido. Llame a esta"Imagen C"

introduzca la descripción de la imagen aquí


  • (x + y) % rand()

Aquí está sumando las coordenadas de píxeles y tomando el resto de la división por un número aleatorio. Si la imagen es 1024x1024 entonces la suma está en el rango [0-2046]. El número aleatorio por el que estás buceando está en el rango [0,RAND_MAX], donde RAND_MAX es al menos 32k y en algunos sistemas es de 2 mil millones. En otras palabras, hay en el mejor de los casos una probabilidad de 1 en 16 de que el resto no sea solo (x + y). Así que en su mayor parte esta función sólo producirá un gradiente de azul creciente hacia la dirección +x + y.

Sin embargo, solo está utilizando los 8 bits más bajos, porque devuelve un uint8_t, por lo que tendrá rayas de gradientes 256 píxeles de ancho.

Llama a esto"Imagen A"

introduzca la descripción de la imagen aquí


  • (x - y) % rand()

Aquí haces algo similar, pero con resta. Mientras x sea mayor que y tendrás algo similar a la imagen anterior. Pero donde y es mayor, el resultado es un número muy grande porque x y y no tienen signo (los resultados negativos se ajustan a la parte superior del rango de tipos sin signo), y luego el % rand() entra en acción y realmente obtienes ruido.

Llame a esta"Imagen B"

introduzca la descripción de la imagen aquí

Luego elige de estas imágenes usando las funciones rand() % 2 y ((x * y % 1024) % rand()) % 2. El primero de ellos se puede leer como elegir con 50% de probabilidad (ignorando los problemas con rand() y sus bits de orden bajo.)

Aquí hay un primer plano de donde rand() % 2 es verdadero (píxeles blancos) por lo que la imagen A está seleccionada.

introduzca la descripción de la imagen aquí

El segundo de nuevo tiene el problema donde rand() es generalmente mayor que la cosa que eres dividiendo, que es como máximo 1023. Pero (x*y%1024)%2 no produce 0 y 1 con la misma frecuencia. Cualquier número impar multiplicado por cualquier número par es par. Cualquier número par multiplicado por cualquier número par también es par. Solo un número impar multiplicado por un número impar es impar, y así %2 en valores que son pares tres cuartas partes del tiempo producirá 0 tres cuartas partes del tiempo.

Así que aquí hay un primer plano de donde ((x * y % 1024) % rand()) % 2 es cierto para que la Imagen B podría ser elegido.

introduzca la descripción de la imagen aquí

Y aquí hay un primer plano de donde la imagen C podría ser seleccionada:

introduzca la descripción de la imagen aquí

Finalmente combinando las condiciones aquí es donde se selecciona la imagen B:

introduzca la descripción de la imagen aquí

Y donde se selecciona la imagen C:

introduzca la descripción de la imagen aquí

La combinación resultante se puede leer como:

Con un 50% de probabilidad use el píxel de la Imagen A. El resto del tiempo elija entre la Imagen B y Imagen C, B donde ambas coordenadas son impares, C donde cualquiera de las dos es par.

Finalmente, dado que estás haciendo lo mismo para tres colores diferentes, pero con diferentes orientaciones, los patrones están orientados de manera diferente en cada color y producen las tiras cruzadas o el patrón de cuadrícula que estás viendo.

 338
Author: bames53,
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
2018-09-22 03:19:34

Muchos de los cálculos que estás haciendo en tu código no te llevarán a valores verdaderamente aleatorios. Esas líneas nítidas que están viendo corresponden a lugares donde los valores relativos de sus coordenadas x e y se intercambian entre sí, y cuando eso sucede estás utilizando fórmulas fundamentalmente diferentes. Por ejemplo, computar (x + y) % rand() generalmente le devolverá el valor x + y, ya que rand() (generalmente) devolverá un número mucho, mucho más grande que x + y dado que RAND_MAX suele ser un número bastante grande numero. En ese sentido, no debes esperar recuperar el ruido blanco, ya que el algoritmo que estás usando para generar cosas está sesgado lejos de generar ruido blanco. Si desea ruido blanco, simplemente establezca cada píxel en rand(). Si desea un patrón agradable como el que tiene arriba, pero con un poco de aleatoriedad arrojado aquí y allá, siga usando el código que ha escrito.

Además, como @pm100 ha señalado en los comentarios, la función rand no devuelve realmente aleatorio números, y en su lugar utiliza una función pseudoaleatoria para producir valores. La implementación predeterminada de rand en muchos sistemas utiliza un tipo de generador de números pseudoaleatorios llamado generador congruente lineal que produce números que en ráfagas cortas pueden parecer aleatorios, pero que son decididamente no random en la práctica. Por ejemplo, aquí hay una animación de Wikipedia que muestra cómo los puntos aleatorios en el espacio elegidos con un generador congruente lineal terminan cayendo en un número fijo de hiperplanos:

Imagen

Si reemplaza las coordenadas x, y y z con las coordenadas R, G y B, esto se ve notablemente similar a la salida que produce su programa. Sospecho que este no es probablemente el tema central aquí, ya que el otro aspecto mencionado anteriormente probablemente será mucho más pronunciado.

Si estás buscando números aleatorios de mayor calidad, necesitarás usar una fuente aleatoria de mayor calidad. En C, usted podría considerar la lectura de bytes de /dev/urandom/ (en un sistema similar a Linux), que da valores aleatorios bastante uniformes. C++ ahora tiene una serie de buenas primitivas de generación de números aleatorios en sus bibliotecas estándar, si eso está disponible para usted.

 44
Author: templatetypedef,
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
2018-09-21 23:25:29