Почему я получаю именно этот образец цвета при использовании rand ()? - PullRequest
0 голосов
/ 22 сентября 2018

Я пытался создать файл изображения, например:

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);
    }
}

Я ожидал получить что-то случайное (белый шум).Однако вывод интересен:

Знаете ли вы причину почему?


Редактировать

Теперь ясно, что это не имеет ничего общего с rand().

Также попробуйте этот код:

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; */
    }

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

Первоначально я собирался получить тот же ответ, что и все остальные, и связать его с проблемами с rand().Однако я подумал, что лучше сделать это, и вместо этого проанализировал распределение, которое фактически производит ваша математика.

TL; DR: шаблон, который вы видите, не имеет ничего общего с базовым генератором случайных чисел, а вместо этого просто связан сспособ, которым ваша программа манипулирует числами.

Я буду придерживаться вашей синей функции, поскольку все они похожи.

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

Каждое значение пикселя выбирается из одной из трех функций: (x + y) % rand(), (x - y) % rand() и rand();

Давайте рассмотрим изображения, созданные каждым из них в отдельности.

  • rand()

Это то, что вы ожидаете, только шум.Назовите это «Изображение C»

enter image description here


  • (x + y) % rand()

Здесь вы добавляетепиксель координирует вместе и берет остаток от деления на случайное число.Если изображение 1024x1024, то сумма находится в диапазоне [0-2046].Случайное число, на которое вы ныряете, находится в диапазоне [0, RAND_MAX], где RAND_MAX составляет не менее 32 КБ, а в некоторых системах - 2 миллиарда.Другими словами, в лучшем случае есть шанс 1 к 16, что остаток не просто (x + y).Таким образом, по большей части эта функция будет просто создавать градиент увеличения синего в направлении + x + y.

Однако вы используете только младшие 8 бит, потому что вы возвращаете uint8_t, так что выбудет иметь полосы градиентов шириной 256 пикселей.

Назовите это "Изображение A"

enter image description here


  • (x - y) % rand()

Здесь вы делаете что-то похожее, но с вычитанием.Пока х больше, чем у, у вас будет что-то похожее на предыдущее изображение.Но там, где y больше, результат - очень большое число, потому что x и y являются беззнаковыми (отрицательные результаты переносятся в верхнюю часть диапазона беззнакового типа), а затем включается % rand(), и вы на самом делеполучить шум.

Назовите это «Изображение B»

enter image description here

Каждый пиксель в вашем окончательном изображении взят из одного из этих трех изображенийиспользуя функции rand() % 2 и ((x * y % 1024) % rand()) % 2.Первый из них может быть прочитан как выбор с вероятностью 50% (игнорируя проблемы с rand() и его младшими битами.)

Вот крупный план, где rand() % 2 является истинным (белые пиксели), поэтому изображение A

enter image description here

Вторая функция ((x * y % 1024) % rand()) % 2 снова имеет проблему, где rand() обычно больше, чем то, что вы делите, (x * y % 1024), что не более 1023. Тогда (x*y%1024)%2 не дает 0 и 1 одинаково часто.Любое нечетное число, умноженное на любое четное число, является четным.Любое четное число, умноженное на любое четное число, также является четным.Только нечетное число, умноженное на нечетное число, является нечетным, и, таким образом, %2 для значений, которые являются четными тремя четвертями времени, даст 0 три четверти времени.

Вот крупный план, где ((x * y % 1024) % rand()) % 2верно, чтобы изображение B можно было выбрать.Он выбирает точно, где обе координаты нечетные.

enter image description here

И вот крупный план того, где можно выбрать изображение C:

enter image description here

Наконец, объединяя условия, вот где выбрано изображение B:

enter image description here

И где изображение Cвыбрано:

enter image description here

Полученную комбинацию можно прочитать как:

С вероятностью 50% используйте пиксель из изображения A. Остальныевыберите время между изображениями B и C, где обе координаты нечетные, C, где любая из них четная.

Наконец, поскольку вы делаете то же самое для трех разных цветов, но с разными ориентациями,узоры ориентированы по-разному в каждом цвете и создают полосы или сетку, которые вы видите.

0 голосов
/ 22 сентября 2018

Многие вычисления, которые вы выполняете в своем коде, не приведут к действительно случайным значениям.Те острые линии, которые вы видите, соответствуют местам, где относительные значения ваших координат x и y торгуют друг с другом, и когда это происходит, вы используете принципиально разные формулы.Например, вычисление (x + y) % rand() обычно возвращает вам значение x + y, поскольку rand() будет (обычно) возвращать число, намного большее, чем x + y, учитывая, что RAND_MAX обычно довольно большое число.В этом смысле вы не должны ожидать возврата белого шума, поскольку алгоритм, который вы используете для генерации вещей, смещен от генерации белого шума.Если вы хотите белый шум, просто установите каждый пиксель на rand().Если вам нужен хороший шаблон, подобный тому, который у вас есть выше, но с небольшой случайностью, добавленной здесь и там, продолжайте использовать код, который вы написали.

Кроме того, как заметил @ pm100в комментариях функция rand не возвращает действительно случайные числа, а вместо этого использует псевдослучайную функцию для получения значений.Реализация по умолчанию rand во многих системах использует тип генератора псевдослучайных чисел, называемый линейный конгруэнтный генератор , который генерирует числа, которые в коротких пакетах могут казаться случайными, но которые на практике явно неслучайны.Например, вот анимация из Википедии, показывающая, как случайные точки в пространстве, выбранные с помощью линейного конгруэнтного генератора, попадают в фиксированное число гиперплоскостей:

The image

Если вы замените x,Координаты y и z с координатами R, G и B выглядят замечательно аналогично выводу, создаваемому вашей программой.Я подозреваю, что это, вероятно, не основная проблема здесь, так как другой аспект, упомянутый выше, вероятно, будет гораздо более выраженным.

Если вы ищете случайные числа более высокого качества, вам нужно использоватьболее качественный случайный источник.В C вы можете рассмотреть чтение байтов из /dev/urandom/ (в Linux-подобной системе), что дает довольно равномерно случайные значения.C ++ теперь имеет несколько хороших примитивов генерации случайных чисел в своих стандартных библиотеках, если это доступно вам.

...