CJam, 28 27 byte
PP+mr_mc\ms]1.mrmqf*"(,)".\
Giải pháp này không dựa trên từ chối. Tôi đang tạo các điểm theo tọa độ cực, nhưng với phân bố bán kính không đồng đều để đạt được mật độ điểm đồng nhất.
Kiểm tra nó ở đây.
Giải trình
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.
Tại sao nó hoạt động? Xem xét một biên độ hẹp của bán kính r
và chiều rộng (nhỏ)dr
. Diện tích xấp xỉ 2π*r*dr
(nếu annulus hẹp, chu vi bên trong và bên ngoài gần như giống hệt nhau và có thể bỏ qua độ cong, sao cho diện tích có thể được coi là hình chữ nhật có chiều dài cạnh chu vi và chiều rộng của annulus). Vì vậy, diện tích tăng tuyến tính với bán kính. Điều này có nghĩa là chúng tôi cũng muốn phân phối tuyến tính của bán kính ngẫu nhiên, để đạt được mật độ không đổi (tại bán kính gấp đôi, có diện tích gấp đôi diện tích, vì vậy chúng tôi muốn gấp đôi số điểm ở đó).
Làm thế nào để chúng ta tạo ra một phân phối ngẫu nhiên tuyến tính từ 0 đến 1? Trước tiên hãy xem xét trường hợp riêng biệt. Giả sử, chúng tôi có phân phối mong muốn gồm 4 giá trị, như {0.1, 0.4, 0.2, 0.3}
(nghĩa là chúng tôi muốn 1
phổ biến gấp 4 lần và phổ biến 0
gấp đôi 2
; chúng tôi muốn 3
phổ biến gấp ba lần 0
):
Làm thế nào có thể chọn một trong bốn giá trị với phân phối mong muốn? Chúng ta có thể xếp chúng lên nhau, chọn một giá trị ngẫu nhiên đồng đều từ 0 đến 1 trên trục y và chọn phân đoạn tại điểm đó:
Có một cách khác để hình dung sự lựa chọn này mặc dù. Thay vào đó, chúng ta có thể thay thế từng giá trị của phân phối bằng sự tích lũy của các giá trị cho đến thời điểm đó:
Và bây giờ chúng ta coi dòng trên cùng của biểu đồ này là một hàm f(x) = y
và đảo ngược nó để có được một hàm , mà chúng ta có thể áp dụng cho một giá trị ngẫu nhiên thống nhất trong :g(y) = f-1(y) = x
y ∈ [0,1]
Thật tuyệt, vậy làm thế nào để có thể sử dụng điều này để tạo ra phân phối tuyến tính của bán kính? Đây là bản phân phối mà chúng tôi muốn:
Bước đầu tiên là tích lũy các giá trị của phân phối. Nhưng phân phối là liên tục, vì vậy thay vì tổng hợp tất cả các giá trị trước đó, chúng tôi lấy một tích phân từ 0
đến r
. Chúng ta có thể dễ dàng giải quyết điều đó một cách phân tích : . Tuy nhiên, chúng tôi muốn điều này được chuẩn hóa, tức là nhân nó với một hằng số sao cho điều này mang lại giá trị tối đa , vì vậy điều chúng tôi thực sự muốn là :∫0r r dr = 1/2 r2
1
r
r2
Và cuối cùng, chúng ta đảo ngược điều này để có được một hàm mà chúng ta có thể áp dụng cho một giá trị thống nhất [0,1]
, trong đó chúng ta có thể thực hiện lại một cách phân tích: đó chỉ là r = √y
, y
giá trị ngẫu nhiên ở đâu:
Đây là một kỹ thuật khá hữu ích, thường có thể được sử dụng để tạo các phân phối đơn giản chính xác (nó hoạt động cho bất kỳ phân phối nào, nhưng đối với các phân phối phức tạp, hai bước cuối cùng có thể phải được giải quyết bằng số). Tuy nhiên, tôi sẽ không sử dụng nó trong trường hợp cụ thể này trong mã sản xuất, bởi vì căn bậc hai, sin và cos rất đắt: sử dụng thuật toán dựa trên từ chối trung bình nhanh hơn nhiều, vì nó chỉ cần cộng và nhân.