Mengapa saya mendapatkan pola warna khusus ini ketika menggunakan rand ()?


170

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


26
cos rand isnt rand - demo yang bagus untuk itu. Ini adalah 100% deterministik
pm100


50
@ pm100: Seperti jawaban bames53 menjelaskan dengan sangat baik, Anda akan mendapatkan pola yang sama bahkan jika Anda menggunakan generator angka acak yang sempurna.
TonyK

13
Alasan pertanyaan: Karena Anda menggunakan koordinat x dan y untuk menghitung nilai piksel, mengapa Anda berharap nilai-nilai itu tidak tergantung pada koordinat? Jika gambarnya terlalu acak, itu yang Anda butuhkan, kan?
Thomas Padron-McCarthy

15
Pelajaran yang diambil: Melakukan hal-hal acak dengan angka acak tidak menghasilkan hasil acak :)
Hagen von Eitzen

Jawaban:


355

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.

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

Setiap nilai pixel dipilih dari salah satu dari tiga fungsi: (x + y) % rand(), (x - y) % rand(), dan rand();

Mari kita lihat gambar yang dihasilkan oleh masing-masing ini saja.

  • rand()

Inilah yang Anda harapkan, hanya kebisingan. Sebut ini "Gambar C"

masukkan deskripsi gambar di sini


  • (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"

masukkan deskripsi gambar di sini


  • (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 xdan ytidak 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"

masukkan deskripsi gambar di sini

Setiap piksel dalam gambar akhir Anda diambil dari salah satu dari tiga gambar ini menggunakan fungsi rand() % 2dan ((x * y % 1024) % rand()) % 2. Yang pertama dapat dibaca sebagai memilih dengan probabilitas 50% (mengabaikan masalah dengan rand()dan bit urutan rendahnya.)

Ini adalah closeup dari mana rand() % 2true (white pixel) sehingga Gambar A dipilih.

masukkan deskripsi gambar di sini

Fungsi kedua ((x * y % 1024) % rand()) % 2lagi memiliki masalah di mana rand()biasanya lebih besar dari hal yang Anda bagikan (x * y % 1024), yaitu paling banyak 1023. Maka (x*y%1024)%2tidak 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 %2nilai-nilai yang bahkan tiga perempat waktu akan menghasilkan 0 tiga perempat waktu.

Ini adalah closeup dari mana ((x * y % 1024) % rand()) % 2benar sehingga Gambar B dapat dipilih. Itu memilih persis di mana kedua koordinat aneh.

masukkan deskripsi gambar di sini

Dan ini adalah gambar close-up di mana Gambar C dapat dipilih:

masukkan deskripsi gambar di sini

Akhirnya menggabungkan kondisi di sinilah Gambar B dipilih:

masukkan deskripsi gambar di sini

Dan di mana Gambar C dipilih:

masukkan deskripsi gambar di sini

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.


45

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 nilai x + y, karena rand()akan (biasanya) mengembalikan angka jauh, jauh lebih besar daripada yang x + ydiberikan yang RAND_MAXbiasanya 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, randfungsi tidak mengembalikan angka yang benar-benar acak, dan sebaliknya menggunakan fungsi pseudorandom untuk menghasilkan nilai-nilai itu. Implementasi default randpada 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:

Foto

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.