CJam, 28 27 byte
PP+mr_mc\ms]1.mrmqf*"(,)".\
Solusi ini bukan berbasis penolakan. Saya menghasilkan titik dalam koordinat kutub, tetapi dengan distribusi yang tidak seragam dari jari-jari untuk mencapai kerapatan titik yang seragam.
Uji di sini.
Penjelasan
PP+ e# Push 2π.
mr_ e# Get a random float between 0 and 2π, make a copy.
mc\ e# Take the cosine of one copy and swap with the other.
ms] e# Take the sine of the other copy and wrap them in an array.
e# This gives us a uniform point on the unit circle.
1.mr e# Get a random float between 0 and 1.
mq e# Take the square root. This is the random radius.
f* e# Multiply x and y by this radius.
"(,)".\ e# Put the resulting numbers in the required format.
Mengapa ini berhasil? Pertimbangkan anulus jari-jari sempit r
dan lebar (kecil)dr
. Daerah tersebut kira-kira 2π*r*dr
(jika annulus sempit, keliling bagian dalam dan luar hampir identik, dan kelengkungan dapat diabaikan, sehingga daerah tersebut dapat diperlakukan sebagai bidang segi empat dengan panjang sisi keliling dan lebar kelengkungan). annulus). Jadi area bertambah secara linear dengan jari-jari. Ini berarti bahwa kami juga menginginkan distribusi linear dari jari-jari acak, untuk mencapai kerapatan konstan (pada radius dua kali, ada area dua kali lebih banyak untuk diisi, jadi kami ingin dua kali lebih banyak titik di sana).
Bagaimana kita menghasilkan distribusi acak linier dari 0 ke 1? Mari kita lihat kasus diskritnya terlebih dahulu. Katakanlah, kami memiliki distribusi yang diinginkan dari 4 nilai, seperti {0.1, 0.4, 0.2, 0.3}
(yaitu kami ingin 1
menjadi 4 kali lebih umum 0
, dan dua kali lebih umum 2
; kami ingin 3
tiga kali lebih umum 0
):
Bagaimana cara memilih satu dari empat nilai dengan distribusi yang diinginkan? Kita dapat menumpuknya, mengambil nilai acak seragam antara 0 dan 1 pada sumbu y dan memilih segmen pada titik itu:
Ada cara berbeda untuk memvisualisasikan pemilihan ini. Sebagai gantinya, kami dapat mengganti setiap nilai distribusi dengan akumulasi nilai hingga saat itu:
Dan sekarang kita memperlakukan baris teratas dari bagan ini sebagai fungsi f(x) = y
dan membalikkannya untuk mendapatkan fungsi , yang dapat kita terapkan pada nilai acak seragam di :g(y) = f-1(y) = x
y ∈ [0,1]
Keren, jadi bagaimana memanfaatkan ini untuk menghasilkan distribusi linear jari-jari? Ini adalah distribusi yang kami inginkan:
Langkah pertama adalah mengakumulasi nilai-nilai distribusi. Tetapi distribusi ini kontinu, jadi alih-alih menjumlahkan semua nilai sebelumnya, kami mengambil integral dari 0
ke r
. Kita dapat dengan mudah memecahkan analitis bahwa: . Namun, kami ingin ini dinormalisasi, yaitu untuk mengalikannya dengan konstanta sehingga memberikan nilai maksimum , jadi yang benar-benar kita inginkan adalah :∫0r r dr = 1/2 r2
1
r
r2
Dan akhirnya, kita membalikkan ini untuk mendapatkan fungsi yang dapat kita terapkan pada nilai yang seragam [0,1]
, yang dapat kita lakukan lagi secara analitis: hanya saja r = √y
, di mana y
adalah nilai acak:
Ini adalah teknik yang cukup berguna yang sering dapat digunakan untuk menghasilkan distribusi sederhana dengan tepat (ini berfungsi untuk distribusi apa pun, tetapi untuk yang rumit, dua langkah terakhir mungkin harus diselesaikan secara numerik). Namun, saya tidak akan menggunakannya dalam kasus khusus ini dalam kode produksi, karena akar kuadrat, sinus dan kosinus sangat mahal: menggunakan algoritma berbasis penolakan rata-rata jauh lebih cepat, karena hanya membutuhkan penambahan dan perkalian.