CJam, 28 27 байт
PP+mr_mc\ms]1.mrmqf*"(,)".\
Це рішення не засноване на відхиленні. Я генерую точки в полярних координатах, але з нерівномірним розподілом радіусів для досягнення рівномірної щільності точок.
Тестуйте це тут.
Пояснення
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.
Чому це працює? Розглянемо вузький колін радіуса r
та (малої) ширини dr
. Площа приблизно2π*r*dr
(якщо кільце вузький, внутрішня і зовнішня окружність майже однакові, і кривизна може бути ігнорована, так що площа може бути розглянута як площа прямокутника із довжиною бічних сторін окружності та шириною відмінність). Отже площа збільшується лінійно з радіусом. Це означає, що ми також хочемо лінійного розподілу випадкових радіусів, щоб досягти постійної щільності (при подвійному радіусі є заповнення вдвічі більше площі, тому ми хочемо там вдвічі більше точок).
Як ми можемо генерувати лінійний випадковий розподіл від 0 до 1? Розглянемо спочатку дискретний випадок. Скажімо, у нас є бажане розподіл 4 значень, наприклад {0.1, 0.4, 0.2, 0.3}
(тобто ми хочемо 1
бути в 4 рази частішими 0
і вдвічі частішими 2
; ми хочемо 3
втричі поширенішими 0
):
Як можна вибрати одне з чотирьох значень із потрібним розподілом? Ми можемо складати їх, вибирати рівномірно випадкове значення між 0 та 1 на осі у та вибирати відрізок у цій точці:
Однак є інший спосіб візуалізації цього вибору. Ми могли замість цього замінити кожне значення розподілу накопиченням значень до цього моменту:
А тепер ми трактуємо верхній рядок цієї діаграми як функцію f(x) = y
та інвертуємо її, щоб отримати функцію , яку ми можемо застосувати до рівномірно випадкового значення у :g(y) = f-1(y) = x
y ∈ [0,1]
Класно, тож як можна скористатися цим для отримання лінійного розподілу радіусів? Цей розподіл ми хочемо:
Перший крок - накопичення значень розподілу. Але розподіл безперервно, так що замість підсумовування за всіма попередніми значеннями, ми беремо інтеграл від 0
до r
. Ми можемо легко вирішити, аналітично: . Однак ми хочемо, щоб це нормалізувалося, тобто помножило його на постійне так, що це дає максимальне значення , так що ми дійсно хочемо :∫0r r dr = 1/2 r2
1
r
r2
І, нарешті, ми інвертуємо це, щоб отримати функцію, до якої можна застосувати рівномірне значення [0,1]
, яке ми можемо знову зробити аналітично: це просто r = √y
, де y
випадкове значення:
Це досить корисна методика, яку часто можна використовувати для генерування простих дистрибутивів (вона працює для будь-якого розподілу, але для складних останні два етапи, можливо, доведеться вирішити чисельно). Однак я б не використовував його в цьому конкретному випадку у виробничому коді, тому що квадратний корінь, синус та косинус є надмірно дорогими: використання алгоритму на основі відкидання в середньому набагато швидше, оскільки воно потребує лише додавання та множення.