Początkowo miałem otrzymać taką samą odpowiedź, jak wszyscy inni i przypisać to do problemów rand()
. Jednak pomyślałem, że lepiej to zrobić i zamiast tego przeanalizowałem rozkład, który faktycznie generuje twoja matematyka.
TL; DR: Wzorzec, który widzisz nie ma nic wspólnego z podstawowym generatorem liczb losowych, a zamiast tego jest po prostu spowodowany sposobem, w jaki twój program manipuluje liczbami.
Będę trzymał się twojej niebieskiej funkcji, ponieważ wszystkie są podobne.
uint8_t blue(uint32_t x, uint32_t y) {
return (rand() % 2) ? (x + y) % rand() :
((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
rand();
}
Każda wartość piksela jest wybrany z jednej z trzech funkcji: (x + y) % rand()
, (x - y) % rand()
i rand()
;
Spójrzmy na obrazy utworzone przez każde z nich samodzielnie.
Tego można się spodziewać, po prostu hałasu. Nazwij to „Obrazem C”
Tutaj dodajesz współrzędne pikseli, a resztę bierzesz z dzielenia przez liczbę losową. Jeśli obraz ma rozmiar 1024x1024, to suma mieści się w zakresie [0-2046]. Losowa liczba, według której nurkujesz, mieści się w zakresie [0, RAND_MAX], gdzie RAND_MAX wynosi co najmniej 32 tys., Aw niektórych systemach wynosi 2 miliardy. Innymi słowy, jest co najwyżej 1 na 16 szans, że reszta nie jest po prostu (x + y)
. Więc w większości ta funkcja po prostu wytworzy gradient rosnącego niebieskiego w kierunku + x + y.
Jednak używasz tylko najniższych 8 bitów, ponieważ zwracasz a uint8_t
, więc będziesz mieć paski gradientów o szerokości 256 pikseli.
Nazwij to „Obrazem A”
Tutaj robisz coś podobnego, ale z odejmowaniem. Dopóki x jest większe niż y, będziesz mieć coś podobnego do poprzedniego obrazu. Ale gdy y jest większe, wynikiem jest bardzo duża liczba, ponieważ x
i y
są bez znaku (wyniki ujemne zawijają się do początku zakresu typu bez znaku), a następnie % rand()
kopnięcia i faktycznie pojawia się szum.
Nazwij to „Obrazem B”
Każdy piksel końcowego obrazu jest pobierany z jednego z tych trzech obrazów przy użyciu funkcji rand() % 2
i ((x * y % 1024) % rand()) % 2
. Pierwszy z nich można odczytać jako wybieranie z 50% prawdopodobieństwem (ignorowanie problemów z rand()
bitami o najniższej kolejności).
Oto zbliżenie miejsca, w którym rand() % 2
jest prawdziwe (białe piksele), więc wybrano Obraz A.
Druga funkcja ((x * y % 1024) % rand()) % 2
znowu ma problem, gdzie rand()
jest zwykle większa niż (x * y % 1024)
dzielona rzecz , która wynosi co najwyżej 1023. Wtedy (x*y%1024)%2
nie daje równorzędnie 0 i 1. Każda liczba nieparzysta pomnożona przez dowolną liczbę parzystą jest parzysta. Każda liczba parzysta pomnożona przez dowolną liczbę parzystą jest również parzysta. Tylko liczba nieparzysta pomnożona przez liczbę nieparzystą jest nieparzysta, a zatem %2
wartości parzyste w trzech czwartych czasu dadzą 0 w trzech czwartych czasu.
Oto zbliżenie miejsca, w którym ((x * y % 1024) % rand()) % 2
jest prawdziwe, aby można było wybrać obraz B. Wybiera dokładnie, gdzie obie współrzędne są nieparzyste.
A oto zbliżenie miejsca, w którym można wybrać Obraz C:
Na koniec łącząc warunki, tutaj wybrano Obraz B:
A gdzie wybrany jest Obraz C:
Wynikową kombinację można odczytać jako:
Z prawdopodobieństwem 50% użyj piksela z obrazu A. Reszta czasu wybierz między obrazem B a obrazem C, B, gdzie obie współrzędne są nieparzyste, C, gdzie jedna z nich jest parzysta.
Wreszcie, ponieważ robisz to samo dla trzech różnych kolorów, ale przy różnych orientacjach, wzory są zorientowane inaczej w każdym kolorze i tworzą przecinające się paski lub wzór siatki, który widzisz.