Я спочатку мав таку саму відповідь, як і всі інші, і вирішував це на вирішення проблем 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()
;
Давайте розглянемо зображення, створені кожним із них окремо.
Це те, чого можна було б очікувати, просто шум. Назвіть це "Зображення C"
Тут ви додаєте піксельні координати разом, а решту ділимо на випадкове число. Якщо зображення 1024x1024, то сума знаходиться в діапазоні [0-2046]. Випадкове число, за яким ви пірнаєте, знаходиться в межах [0, RAND_MAX], де RAND_MAX становить щонайменше 32 к, а в деяких системах - 2 мільярди. Іншими словами, є в кращому випадку шанс 1 на 16, що решта не просто (x + y)
. Таким чином, здебільшого ця функція буде просто створювати градієнт збільшення синього до + x + y напрямку.
Однак ви використовуєте лише найнижчі 8 біт, тому що ви повертаєте a uint8_t
, тож у вас будуть смуги градієнтів шириною 256 пікселів.
Назвіть це "Зображення"
Тут ви робите щось подібне, але з відніманням. Поки х більший за y, ви матимете щось подібне до попереднього зображення. Але там , де у більше, то результат буде дуже велике число , так як x
і y
без знака (негативні результати обернути навколо верхньої частини діапазону тип без знака в), а потім в % rand()
кайф, і ви дійсно отримаєте шум.
Назвіть це "Зображення B"
Кожен піксель остаточного зображення знімається з одного з цих трьох зображень за допомогою функцій rand() % 2
та ((x * y % 1024) % rand()) % 2
. Перший з них можна читати як вибір з 50% -ною ймовірністю (ігнорування проблем із rand()
бітами низького порядку).
Ось крупний план, де rand() % 2
відповідає дійсності (білі пікселі), тому вибрано зображення A.
Друга функція ((x * y % 1024) % rand()) % 2
знову має проблему, де rand()
зазвичай більше, ніж річ, яку ви розділяєте (x * y % 1024)
, яка становить максимум 1023. Тоді (x*y%1024)%2
не виробляється 0 і 1 однаково часто. Будь-яке непарне число, помножене на будь-яке парне число, парне. Будь-яке парне число, помножене на будь-яке парне число, також є парним. Лише непарне число, помножене на непарне число, непарне, і тому %2
значення, які складають навіть три чверті часу, дадуть 0 три чверті часу.
Ось детальний опис того, де ((x * y % 1024) % rand()) % 2
це правда, щоб можна було вибрати зображення B. Це вибір саме там, де обидві координати непарні.
І ось крупний план, де можна вибрати зображення C:
Нарешті, поєднуючи умови тут, де обрано зображення B:
І де обрано зображення C:
Отриману комбінацію можна прочитати як:
З 50% -ною ймовірністю використовуйте піксель із зображення А. Решту часу вибирайте між зображенням B і зображенням C, B, коли обидві координати непарні, C, де будь-яка парна.
Нарешті, оскільки ви робите те ж саме для трьох різних кольорів, але з різною орієнтацією, візерунки орієнтовані по-різному в кожному кольорі і випускаєте схрещувальні смуги або візерунок сітки, яку ви бачите.