Saya mencoba membuat file gambar, seperti ini:
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);
}
}
Saya berharap mendapatkan sesuatu yang acak (white noise). Namun, hasilnya menarik:
Apakah Anda tahu alasannya?
Edit
Sekarang, jelas bahwa itu tidak ada hubungannya dengan rand()
.
Coba juga kode ini:
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; */
}
Jawaban:
Saya awalnya akan memiliki jawaban yang sama seperti yang dimiliki orang lain dan membahasnya sampai masalah
rand()
. Namun, saya pikir lebih baik melakukannya dan bukannya menganalisis distribusi matematika Anda yang sebenarnya menghasilkan.TL; DR: Pola yang Anda lihat tidak ada hubungannya dengan penghasil bilangan acak yang mendasarinya dan sebagai gantinya hanya karena cara program Anda memanipulasi angka-angka tersebut.
Saya akan tetap menggunakan fungsi biru Anda karena semuanya mirip.
Setiap nilai pixel dipilih dari salah satu dari tiga fungsi:
(x + y) % rand()
,(x - y) % rand()
, danrand()
;Mari kita lihat gambar yang dihasilkan oleh masing-masing ini saja.
rand()
Inilah yang Anda harapkan, hanya kebisingan. Sebut ini "Gambar C"
(x + y) % rand()
Di sini Anda menambahkan koordinat piksel bersama dan mengambil sisanya dari pembagian dengan angka acak. Jika gambar adalah 1024x1024 maka jumlahnya berada dalam kisaran [0-2046]. Angka acak yang Anda lewati berada dalam kisaran [0, RAND_MAX], di mana RAND_MAX setidaknya 32k dan pada beberapa sistem adalah 2 miliar. Dengan kata lain, paling tidak ada peluang 1 dari 16 bahwa sisanya tidak adil
(x + y)
. Jadi untuk sebagian besar fungsi ini hanya akan menghasilkan gradien biru yang meningkat ke arah + x + y.Namun Anda hanya menggunakan 8 bit terendah, karena Anda mengembalikan a
uint8_t
, sehingga Anda akan memiliki garis gradien lebar 256 piksel.Sebut ini "Gambar A"
(x - y) % rand()
Di sini Anda melakukan sesuatu yang serupa, tetapi dengan pengurangan. Selama x lebih besar dari y Anda akan memiliki sesuatu yang mirip dengan gambar sebelumnya. Tapi di mana y lebih besar, hasilnya adalah angka yang sangat besar karena
x
dany
tidak ditandatangani (hasil negatif membungkus ke bagian atas kisaran jenis unsigned), dan kemudian% rand()
tendangan masuk dan Anda benar-benar mendapatkan suara.Sebut ini "Gambar B"
Setiap piksel dalam gambar akhir Anda diambil dari salah satu dari tiga gambar ini menggunakan fungsi
rand() % 2
dan((x * y % 1024) % rand()) % 2
. Yang pertama dapat dibaca sebagai memilih dengan probabilitas 50% (mengabaikan masalah denganrand()
dan bit urutan rendahnya.)Ini adalah closeup dari mana
rand() % 2
true (white pixel) sehingga Gambar A dipilih.Fungsi kedua
((x * y % 1024) % rand()) % 2
lagi memiliki masalah di manarand()
biasanya lebih besar dari hal yang Anda bagikan(x * y % 1024)
, yaitu paling banyak 1023. Maka(x*y%1024)%2
tidak menghasilkan 0 dan 1 sama sering. Angka ganjil yang dikalikan dengan angka genap adalah genap. Angka genap mana pun dikalikan dengan angka genap juga genap. Hanya angka ganjil dikalikan dengan angka ganjil yang ganjil, dan begitu juga%2
nilai-nilai yang bahkan tiga perempat waktu akan menghasilkan 0 tiga perempat waktu.Ini adalah closeup dari mana
((x * y % 1024) % rand()) % 2
benar sehingga Gambar B dapat dipilih. Itu memilih persis di mana kedua koordinat aneh.Dan ini adalah gambar close-up di mana Gambar C dapat dipilih:
Akhirnya menggabungkan kondisi di sinilah Gambar B dipilih:
Dan di mana Gambar C dipilih:
Kombinasi yang dihasilkan dapat dibaca sebagai:
Dengan probabilitas 50%, gunakan piksel dari Gambar A. Sisa waktu memilih antara Gambar B dan Gambar C, B di mana kedua koordinatnya aneh, C di mana salah satu genap.
Akhirnya, karena Anda melakukan hal yang sama untuk tiga warna yang berbeda, tetapi dengan orientasi yang berbeda, polanya diorientasikan secara berbeda pada setiap warna dan menghasilkan garis silang atau pola kisi yang Anda lihat.
sumber
Banyak perhitungan yang Anda lakukan dalam kode Anda tidak akan menghasilkan nilai yang benar-benar acak. Garis-garis tajam yang Anda lihat terkait dengan tempat-tempat di mana nilai relatif x dan y Anda berkoordinasi satu sama lain, dan ketika itu terjadi Anda menggunakan rumus yang berbeda secara fundamental. Sebagai contoh, komputasi
(x + y) % rand()
umumnya akan memberi Anda kembali nilaix + y
, karenarand()
akan (biasanya) mengembalikan angka jauh, jauh lebih besar daripada yangx + y
diberikan yangRAND_MAX
biasanya angka yang cukup besar. Dalam hal itu, Anda seharusnya tidak mengharapkan untuk mendapatkan white noise, karena algoritma yang Anda gunakan untuk menghasilkan sesuatu bias jauh dari menghasilkan white noise. Jika Anda ingin white noise, cukup atur setiap piksel kerand()
. Jika Anda ingin pola yang bagus seperti yang Anda miliki di atas, tetapi dengan sedikit keacakan melemparkan di sana-sini, terus menggunakan kode yang Anda tulis.Selain itu, seperti yang dicatat oleh @ pm100 dalam komentar,
rand
fungsi tidak mengembalikan angka yang benar-benar acak, dan sebaliknya menggunakan fungsi pseudorandom untuk menghasilkan nilai-nilai itu. Implementasi defaultrand
pada banyak sistem menggunakan jenis pseudorandom number generator yang disebut linear congruential generator yang menghasilkan angka yang dalam semburan singkat dapat tampak acak, tetapi yang jelas nonrandom dalam praktiknya. Misalnya, inilah animasi dari Wikipedia yang menunjukkan bagaimana titik-titik acak di ruang angkasa yang dipilih dengan generator kongruensi linear akhirnya jatuh ke sejumlah pesawat tetap:Jika Anda mengganti koordinat x, y, dan z dengan koordinat R, G, dan B, ini terlihat sangat mirip dengan output yang dihasilkan oleh program Anda. Saya menduga bahwa ini mungkin bukan masalah inti di sini, karena aspek lain yang disebutkan di atas mungkin akan jauh lebih jelas.
Jika Anda mencari angka acak berkualitas tinggi, Anda harus menggunakan sumber acak berkualitas lebih tinggi. Di C, Anda dapat mempertimbangkan membaca byte dari
/dev/urandom/
(pada sistem mirip Linux), yang memberikan nilai acak yang cukup seragam. C ++ sekarang memiliki sejumlah primitif generasi nomor acak yang baik di perpustakaan standarnya, jika tersedia untuk Anda.sumber