Створити випадкову точку в колі (рівномірно)


212

Я повинен генерувати рівномірно випадкову точку всередині кола радіуса R .

Я розумію, що просто підібравши рівномірно випадковий кут в проміжку [0 ... 2π) і рівномірно випадковий радіус в проміжку (0 ... R ), я отримав би більше точок у напрямку до центру, оскільки для двох заданих радіуси, точки на меншому радіусі будуть ближче один до одного, ніж для точок на великому радіусі.

Я знайшов запис в блозі з цього приводу тут , але я не розумію його міркування. Я припускаю, що це правильно, але я дуже хотів би зрозуміти, звідки він отримує (2 / R 2 ) × r і як він отримує остаточне рішення.


Оновлення: 7 років після опублікування цього питання я все ще не отримав задовільної відповіді на власне питання щодо математики, що лежить в алгоритмі квадратного кореня. Тому я провів день, пишучи відповідь. Посилання на мою відповідь .


18
Чи є недолік вибірки відхилень справді великою справою? Очікувана кількість необхідних спроб становить 4 / π ≈ 1,27, і ймовірність того, що вам потрібно більше, ніж k спроб, становить (1-π / 4) ^ k. Для k = 20 це ≈ .00000000000004, а для k = 50 - порядку 10 ^ {- 34}. Ви можете приймати ці шанси в будь-який день; ти зробиш добре.
ShreevatsaR

3
Насправді вибірка відхилень дає гарантію припинення. Шанси нескінченно низькі (якщо бути точним, нульовим), що ваш алгоритм ніколи не припинить.
Джаред Нільсен

2
На мою думку, важливість недоліку відбору проб відхилення пропорційна простоті використання методу вибірки, який дозволяє уникнути відторгнення. У цьому випадку недолік важливий, оскільки вибірка без відхилення проста.
spex

4
@spex На практиці техніка відторгнення швидша, оскільки дозволяє уникнути необхідності в оцінці трансцендентальної функції.
pjs

2
(продовження) відхилення: 0,52 сек. Усі дали однакові засоби та стандартні відхилення (до 3 сиг. рис.). Як і очікувалося, вибірка відхилення не вдалася 27% часу (4 / pi-1), тому було потрібно на 27% більше випадкових чисел, ніж btilly, але на 15% менше, ніж sigfpe. Це підтверджує зауваження pjs та інших осіб про те, що вибірки відхилень є, мабуть, найкращим підходом, якщо тільки наряди не дуже дорогі для отримання.
Пітер Девідсон

Відповіді:


189

Давайте підійдемо до цього, як мав би Архімед.

Як ми можемо генерувати точку рівномірно в трикутнику ABC, де | AB | = | BC |? Давайте полегшимо це, поширивши на паралелограм ABCD. Легко генерувати очки рівномірно в ABCD. Ми рівномірно вибираємо випадкову точку X на AB і Y на BC і вибираємо Z таким, що XBYZ - паралелограм. Щоб отримати рівномірно обрану точку в оригінальному трикутнику, ми просто складемо будь-які точки, які з’являються в АЦП назад, до ABC вздовж змінного струму.

Тепер розглянемо коло. На межі ми можемо думати про це як нескінченно багато трикутників трикутників ABC з B на початку та A і C по окружності, що стикаються близько один до одного. Ми можемо вибрати один із цих трикутників, просто вибравши куту тети. Отже, нам зараз потрібно генерувати відстань від центру, вибравши крапку в повзунку ABC. Знову продовжуйте до ABCD, де D зараз удвічі більше радіуса від центру кола.

Вибрати випадкову точку в ABCD легко, використовуючи описаний вище метод. Виберіть випадкову точку на AB. Рівномірно виберіть випадкову точку на BC. Тобто виберіть пару випадкових чисел x і y рівномірно на [0, R], даючи відстані від центру. Наш трикутник - тонка перемичка, тому AB і BC по суті паралельні. Отже точка Z - це просто відстань x + y від початку. Якщо x + y> R відкидаємо назад.

Ось повний алгоритм для R = 1. Я сподіваюся, ви згодні, що це досить просто. Він використовує триггер, але ви можете дати гарантію, скільки часу це займе, і скільки random()дзвінків йому потрібно, на відміну від вибірки відхилення.

t = 2*pi*random()
u = random()+random()
r = if u>1 then 2-u else u
[r*cos(t), r*sin(t)]

Ось це в Mathematica.

f[] := Block[{u, t, r},
  u = Random[] + Random[];
  t = Random[] 2 Pi;
  r = If[u > 1, 2 - u, u];
  {r Cos[t], r Sin[t]}
]

ListPlot[Table[f[], {10000}], AspectRatio -> Automatic]

введіть тут опис зображення


6
@Karelzarath Мені подобається контрінтуїтивне поняття нескінченно тонкого трикутника, яке все ще ширше на іншому кінці :-) Це отримує правильну відповідь.
sigfpe

2
@hammar Не впевнений, що це добре узагальнено до n вимірів. Але для 3d ви можете використовувати інший результат Архімеда! Використовуйте теорему "капелюшна коробка", щоб створити крапку на циліндрі (просто!), А потім перенесіть її назад у сферу. Це дає напрямок. Тепер скористайтеся random()+random()+random()більш складним складанням (тобто 6-ти сторонній складкою нескінченно тонкого паралелепіпеда до тераедра). Не переконаний, що це хороший метод.
sigfpe

2
Я подумав 1 хв, щоб з'ясувати різницю між випадковим () + випадковим () та 2 * випадковим () ... Я такий дурний: /
JiminP

3
@Tharwen Зауважте, як у колі є більше точок на радіусі 0,9-1,0, ніж на радіусі 0,0-0,1. random () + random () генерує радіуси, швидше за все, приблизно 1,0, але лежать у межах 0,0-2,0. У складеному вигляді вони, швидше за все, становлять близько 1,0 і завжди знаходяться в межах 0,0-1,0. Більше того, це саме пропорція, необхідна в першому реченні цього коментаря. Лише вдвічі виходить більше цифр, що знаходяться біля позначки 0,5, і це було б неправильно.
sigfpe

2
@Tharwen Спробуйте використовувати обидві схеми для отримання випадкових чисел і побачити, що ви отримаєте. 2 * random () дає числа, рівномірно розподілені в діапазоні від 0 до 2. випадкові () + випадкові () дає вам числа в діапазоні від 0 до 2, але (як правило) буде більше чисел, що знаходяться поблизу 1,0, ніж близько 0,0 або 2,0. Це все одно, що коливання двох кубиків та підсумовування швидше дають 7, ніж будь-яке інше число.
sigfpe

133

Як генерувати випадкову точку в колі радіуса R :

r = R * sqrt(random())
theta = random() * 2 * PI

(Припустимо, random()що значення має між 0 і 1 рівномірно)

Якщо ви хочете перетворити це на декартові координати, ви можете зробити це

x = centerX + r * cos(theta)
y = centerY + r * sin(theta)


Чому sqrt(random())?

Давайте розглянемо математику, яка веде до sqrt(random()). Припустимо для простоти, що ми працюємо з одиничним колом, тобто R = 1.

Середня відстань між точками має бути однаковою незалежно від того, наскільки далеко ми від центру дивимось. Це означає, наприклад, що, дивлячись на периметр кола з окружністю 2, ми повинні знайти вдвічі більше точок, ніж кількість точок по периметру кола з окружністю 1.


                

Оскільки окружність кола (2π r ) лінійно зростає з r , то випливає, що кількість випадкових точок повинно лінійно зростати з r . Іншими словами, потрібна щільність функції (PDF) лінійно зростає. Оскільки PDF має мати площу, рівну 1, а максимальний радіус - 1, у нас є


                

Отже, ми знаємо, як повинна виглядати бажана щільність наших випадкових значень. Тепер: Як ми можемо генерувати таке випадкове значення, коли все, що ми маємо, є рівномірним випадковим значенням між 0 і 1?

Ми використовуємо трюк, який називається вибіркою зворотного перетворення

  1. З PDF створіть функцію накопичувального розподілу (CDF)
  2. Дзеркало це вздовж y = x
  3. Застосуйте отриману функцію до рівномірного значення між 0 і 1.

Звучить складно? Дозвольте мені вставити блок-котирування з невеликою бічною доріжкою, яка передає інтуїцію:

Припустимо, ми хочемо генерувати випадкову точку з таким розподілом:

                

Це є

  • 1/5 точок рівномірно між 1 і 2, і
  • 4/5 балів рівномірно між 2 і 3.

CDF, як випливає з назви, є сукупною версією PDF. Інтуїтивно зрозуміло: хоча PDF ( x ) описує кількість випадкових значень на x , CDF ( x ) описує кількість випадкових значень менше x .

У цьому випадку CDF виглядатиме так:

                

Щоб побачити, як це корисно, уявіть, що ми стріляємо кулями зліва направо на рівномірно розподіленій висоті. Коли кулі потрапляють у лінію, вони опускаються на землю:

                

Подивіться, як щільність куль на землі відповідає нашому бажаному розподілу! Ми майже там!

Проблема полягає в тому, що для цієї функції вісь y - вихід, а вісь x - вхід . Ми можемо лише «стріляти кулями з землі прямо вгору»! Нам потрібна обернена функція!

Ось чому ми відображаємо все це; x стає y і y стає x :

                

Ми називаємо це CDF -1 . Для отримання значень відповідно до потрібного розподілу використовуємо CDF -1 (випадковий ()).

… Так, повернемося до генерації випадкових значень радіуса, де наш PDF дорівнює 2 x .

Крок 1: Створіть CDF:

Оскільки ми працюємо з реалами, CDF виражається як інтеграл PDF.

CDF ( x ) = ∫ 2 x = x 2

Крок 2: Дзеркало CDF вздовж y = x :

Математично це зводиться до заміни x і y та вирішення для y :

CDF :      y = x 2
Зміна:    x = y 2
Розв’яжіть:    y = √ x
CDF -1 :   y = √ x

Крок 3: Застосуйте отриману функцію до рівномірного значення між 0 і 1

CDF -1 (випадковий ()) = √ випадковий ()

Що ми маємо на меті отримати :-)


Цей алгоритм можна використовувати для ефективного генерування точок на рингу.
Іван Ковтун

На рингу? Як із фіксованим радіусом? Не впевнений, чи розумію я ваше запитання, але якщо у вас фіксований радіус, вам просто потрібно рандомізувати кут.
aioobe

2
Я спробував використати більш просте слово "Кільце" замість Annulus - область, обмежена двома концентричними колами. У такому випадку алгоритм відхилення стає неефективним, і перший алгоритм верху важко узагальнити. І кутовий корпус з одним радіусом також покритий вашим алгоритмом. Ми завжди генеруємо радіус як sqrt (випадковий (min_radius ^ 2, max_radius ^ 2)), навіть коли min_radius == max_radius.
Іван Ковтун

1
О, гарно! Щоб було зрозуміло, коли ви говорите random(min_radius², max_radius²), ви маєте на увазі щось еквівалентне random() * (max_radius² - min_radius²) + min_radius², де random()повертає однакове значення між 0 і 1?
aioobe

так, саме так я маю на увазі: радіус = sqrt (випадковий () * (max_radius² - min_radius²) + min_radius²).
Іван Ковтун

27

Ось швидке і просте рішення.

Виберіть два випадкових числа в діапазоні (0, 1), а саме aі b. Якщо b < a, поміняйте їх. Ваша думка (b*R*cos(2*pi*a/b), b*R*sin(2*pi*a/b)).

Ви можете подумати над цим рішенням наступним чином. Якщо ви взяли коло, вирізали його, а потім випрямили, у вас вийде прямокутний трикутник. Масштаб цього трикутника вниз, і ви б трикутник від (0, 0)до (1, 0)до (1, 1)і назад в (0, 0). Всі ці перетворення рівномірно змінюють щільність. Що ви зробили, рівномірно вибрали випадкову точку в трикутнику і перевернули процес, щоб отримати точку в колі.


Це, чомусь, дає мені набагато більш рівномірний розподіл, ніж прийнята відповідь, хоча мені потрібно було ділити координату на радіус, інакше це всередині кола R ^ 2
Грег Заал

3
Дякуємо, це ваш код на Java, можливо, хтось вважатиме його корисним: float random1 = MathUtils.random (); float random2 = MathUtils.random (); float randomXPoint = random2 * radius MathUtils.cos (MathUtils.PI2 * random1 / random2); float randomYPoint = random2 * radius MathUtils.sin (MathUtils.PI2 * random1 / random2);
Тоні Серальва

дуже добре! Мені подобається ідея більшої ймовірності централізації балів, тому, якщо ми не поміняємо місцями, коли b < aзможемо досягти цього! наприклад, у javascript jsfiddle.net/b0sb5ogL/1
Guilherme

Я думаю, що ваше рішення є поганим. Це не дає рівномірних результатів. Перевірте цей знімок екрана prntscr.com/fizxgc
bolec_kolec

4
Чи можете ви пояснити трохи більше, як вирізати коло і випрямити його?
kec

21

Зверніть увагу , що щільність точок в пропорційно обернено пропорційно квадрату радіусу, отже , замість того , щоб вибрати rз [0, r_max], вибрати з [0, r_max^2], а потім обчислити свої координати , як:

x = sqrt(r) * cos(angle)
y = sqrt(r) * sin(angle)

Це дасть вам рівномірний розподіл точок на диску.

http://mathworld.wolfram.com/DiskPointPicking.html


12

Подумайте про це так. Якщо у вас прямокутник, де одна вісь є радіусом, а одна - кутом, і ви берете точки всередині цього прямокутника, які знаходяться біля радіуса 0. Усі вони будуть падати дуже близько до початку (тобто близько до кола). Однак, точки біля радіуса R, всі вони впадуть біля краю кола (тобто далеко один від одного.)

Це може дати вам деяке уявлення, чому ви отримуєте таку поведінку.

Коефіцієнт, отриманий на цьому посиланні, говорить вам про те, скільки відповідної площі у прямокутнику потрібно відкоригувати, щоб вона не залежала від радіуса, як тільки вона буде відображена у коло.

Редагувати: Отже, що він пише у посиланні, яким ви ділитесь, це: "Це досить просто зробити, обчисливши обернену сукупний розподіл, і ми отримаємо для r:".

Основна передумова тут полягає в тому, що ви можете створити змінну з потрібним розподілом з рівномірного, зіставивши уніформу за зворотною функцією функції кумулятивного розподілу потрібної функції щільності ймовірності. Чому? Просто сприйміть це як належне, але це факт.

Ось моє інтуїтивне пояснення математики. Функція густини f (r) по відношенню до r повинна бути пропорційною самій r. Розуміння цього факту є частиною будь-якої основної книги обчислення. Дивіться розділи про елементи полярної області. Деякі інші плакати згадували про це.

Тож ми назвемо це f (r) = C * r;

Це виявляється більшу частину роботи. Тепер, оскільки f (r) має бути щільністю ймовірності, ви легко бачите, що, інтегруючи f (r) через інтервал (0, R), ви отримуєте, що C = 2 / R ^ 2 (це вправа для читача .)

Таким чином, f (r) = 2 * r / R ^ 2

Гаразд, тому саме так ви отримуєте формулу за посиланням.

Тоді, заключна частина йде від рівномірної випадкової величини u в (0,1), ви повинні відобразити зворотну функцію функції кумулятивного розподілу від цієї бажаної щільності f (r). Щоб зрозуміти, чому це так, вам потрібно знайти розширений текст ймовірності на зразок Папуліса, мабуть (або отримати його самостійно.)

Інтегруючи f (r), ви отримуєте F (r) = r ^ 2 / R ^ 2

Щоб знайти зворотну функцію цього, ви встановите u = r ^ 2 / R ^ 2, а потім вирішите для r, що дає вам r = R * sqrt (u)

Це також має сенс інтуїтивно зрозуміло, що u = 0 має відображатись на r = 0. Крім того, u = 1 має відображатись на r = R. Крім того, він виконує функцію квадратного кореня, яка має сенс і відповідає посиланням.


10

Причина, чому наївне рішення не працює, полягає в тому, що воно дає більш високу щільність ймовірностей точкам, ближчим до центру кола. Іншими словами, коло, яке має радіус r / 2, має ймовірність r / 2 отримати обрану в ньому точку, але воно має площу (кількість точок) pi * r ^ 2/4.

Тому ми хочемо, щоб щільність вірогідності радіуса мала таке властивість:

Імовірність вибору радіуса, меншого або рівного даному r, повинна бути пропорційна площі кола з радіусом r. (тому що ми хочемо, щоб рівномірний розподіл на точки, а великі площі означали більше балів)

Іншими словами, ми хочемо, щоб ймовірність вибору радіуса між [0, r] дорівнювала його частці від загальної площі кола. Загальна площа кола - pi * R ^ 2, а площа кола з радіусом r - pi * r ^ 2. Таким чином, ми хотіли б, щоб ймовірність вибору радіуса між [0, r] була (pi * r ^ 2) / (pi * R ^ 2) = r ^ 2 / R ^ 2.

Тепер приходить математика:

Ймовірність вибору радіуса між [0, r] є інтегралом p (r) dr від 0 до r (це лише тому, що ми додаємо всі ймовірності менших радіусів). Таким чином, ми хочемо інтеграл (p (r) dr) = r ^ 2 / R ^ 2. Ми можемо чітко бачити, що R ^ 2 - це константа, тому все, що нам потрібно зробити, - це розібратися, який p (r) при інтеграції дав би нам щось на зразок r ^ 2. Відповідь чітко r * константа. інтеграл (r * константа dr) = r ^ 2/2 * константа. Це повинно бути рівним r ^ 2 / R ^ 2, тому постійним = 2 / R ^ 2. Таким чином, у вас є розподіл ймовірностей p (r) = r * 2 / R ^ 2

Примітка. Ще один більш інтуїтивний спосіб роздумувати над проблемою - уявити, що ви намагаєтеся надати кожному колу щільності ймовірності радіуса ra, рівній пропорції кількості точок, які він має по його окружності. Таким чином, коло, яке має радіус r, матиме 2 * pi * r "точки" по його окружності. Загальна кількість балів - pi * R ^ 2. Таким чином, ви повинні дати вірогідності кола кола, рівну (2 * pi * r) / (pi * R ^ 2) = 2 * r / R ^ 2. Це набагато простіше для розуміння та інтуїтивніше, але це не так вже й математично добре.


9

Нехай ρ (радіус) і φ (азимут) - дві випадкові величини, що відповідають полярним координатам довільної точки всередині кола. Якщо точки розподілені рівномірно, то яка функція розподілу ρ і φ?

Для будь-якого r: 0 <r <R ймовірність радіусної координати ρ бути меншою, ніж r

P [ρ <r] = P [точка знаходиться в колі радіуса r] = S1 / S0 = (r / R) 2

Де S1 і S0 - площі кола радіусів r і R відповідно. Таким чином, CDF можна подати у вигляді:

          0          if r<=0
  CDF =   (r/R)**2   if 0 < r <= R
          1          if r > R

І PDF:

PDF = d/dr(CDF) = 2 * (r/R**2) (0 < r <= R).

Зауважимо, що для R = 1 випадкова величина sqrt (X), де X є рівномірною [0, 1), має такий точний CDF (тому що P [sqrt (X) <y] = P [x <y ** 2] = y * * 2 при 0 <y <= 1).

Розподіл φ очевидно рівномірний від 0 до 2 * π. Тепер ви можете створити випадкові полярні координати та перетворити їх на декартові, використовуючи тригонометричні рівняння:

x = ρ * cos(φ)
y = ρ * sin(φ)

Не вдається опублікувати код python для R = 1.

from matplotlib import pyplot as plt
import numpy as np

rho = np.sqrt(np.random.uniform(0, 1, 5000))
phi = np.random.uniform(0, 2*np.pi, 5000)

x = rho * np.cos(phi)
y = rho * np.sin(phi)

plt.scatter(x, y, s = 4)

Ти отримаєш

введіть тут опис зображення


7

Це дійсно залежить від того, що ви маєте на увазі під "рівномірно випадковим". Це тонкий момент, і ви можете прочитати більше про нього на сторінці вікі тут: http://en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29 , де та сама проблема, даючи різні інтерпретації для «рівномірно випадкових» дає різні відповіді!

Залежно від того, як ви вибираєте точки, розподіл може змінюватись, навіть якщо вони є певним чином випадковими у певному сенсі.

Схоже, що запис у блозі намагається зробити його рівномірним випадковим у такому сенсі: Якщо ви берете підколо коло, з тим самим центром, то ймовірність того, що точка падає в цьому регіоні, пропорційна площі регіон. Я вважаю, що це намагається дотримуватися стандартної інтерпретації "рівномірно випадкових" для двовимірних регіонів із визначеними на них областями : ймовірність попадання точки в будь-який регіон (з чітко визначеною областю) пропорційна площі цього регіону.


5
А точніше, ймовірність того, що точка падає в будь-якому довільному регіоні, пропорційна площі регіону - якщо припустити, що область має площу .
ShreevatsaR

@Shree: Правильно, що я мав на увазі під своїм твердженням у дужках. Я зроблю це зрозуміліше, дякую. btw, що стосується блогу, не було реальних доказів того, що довільні області дають пропорційні ймовірності, отже, я вибрав це так.

6

Ось мій код Python для генерування numвипадкових точок із кола радіуса rad:

import matplotlib.pyplot as plt
import numpy as np
rad = 10
num = 1000

t = np.random.uniform(0.0, 2.0*np.pi, num)
r = rad * np.sqrt(np.random.uniform(0.0, 1.0, num))
x = r * np.cos(t)
y = r * np.sin(t)

plt.plot(x, y, "ro", ms=1)
plt.axis([-15, 15, -15, 15])
plt.show()

1
Чому б не просто r = np.sqrt(np.random.uniform(0.0, rad**2, num))?

4

Я думаю, що в цьому випадку використання полярних координат - це спосіб ускладнити проблему, було б набагато простіше, якби вибираєте випадкові точки в квадрат зі сторонами довжиною 2R, а потім вибираєте такі точки (x,y), що x^2+y^2<=R^2.


Ви маєте на увазі x ^ 2 + y ^ 2 <= R ^ 2 Я думаю.
sigfpe

1
Це вибірки відхилення. Це нормально, але означає, що час розрахунку дещо змінюється, що може бути проблемою.
Стів Беннетт

Всі квадрати 4-х сторонні.
xaxxon

Цей алгоритм є більш ефективним, ніж будь-що, що включає квадратні корені або обчислення sin / cos. Він відхиляє менше 21,5% балів квадрата.
Іван Ковтун

3

Рішення в Java та приклад розподілу (2000 балів)

public void getRandomPointInCircle() {
    double t = 2 * Math.PI * Math.random();
    double r = Math.sqrt(Math.random());
    double x = r * Math.cos(t);
    double y = r * Math.sin(t);
    System.out.println(x);
    System.out.println(y);
}

Розподіл 2000 балів

на основі рішення previus https://stackoverflow.com/a/5838055/5224246 від @sigfpe


2

Спочатку ми генеруємо cdf [x], який є

Ймовірність того, що точка менша відстані x від центру кола. Припустимо, коло має радіус R.

очевидно, якщо x дорівнює нулю, тоді cdf [0] = 0

очевидно, якщо x є R, тоді cdf [R] = 1

очевидно, якщо x = r, тоді cdf [r] = (Pi r ^ 2) / (Pi R ^ 2)

Це тому, що кожна «маленька площа» на колі має однакову ймовірність вибору, тому ймовірність пропорційна площі, про яку йдеться. А площа, задана відстань х від центру кола, є Pi r ^ 2

так cdf [x] = x ^ 2 / R ^ 2, оскільки Pi скасовують один одного

у нас є cdf [x] = x ^ 2 / R ^ 2, де x іде від 0 до R

Тому ми вирішуємо для x

R^2 cdf[x] = x^2

x = R Sqrt[ cdf[x] ]

Тепер ми можемо замінити cdf випадковим числом від 0 до 1

x = R Sqrt[ RandomReal[{0,1}] ]

Нарешті

r = R Sqrt[  RandomReal[{0,1}] ];
theta = 360 deg * RandomReal[{0,1}];
{r,theta}

отримуємо полярні координати {0.601168 R, 311.915 град}


1

Існує лінійна залежність між радіусом і кількістю точок "біля" цього радіуса, тому йому потрібно використовувати розподіл радіуса, який також робить кількість точок даних біля радіуса rпропорційною r.


1

Я використовував один раз цей метод: Це може бути абсолютно неоптимізованим (тобто він використовує масив точок, тому його не можна використовувати для великих кіл), але дає достатньо випадкового розподілу. Ви можете пропустити створення матриці і намалювати безпосередньо, якщо хочете. Метод полягає в рандомізації всіх точок прямокутника, які потрапляють всередину кола.

bool[,] getMatrix(System.Drawing.Rectangle r) {
    bool[,] matrix = new bool[r.Width, r.Height];
    return matrix;
}

void fillMatrix(ref bool[,] matrix, Vector center) {
    double radius = center.X;
    Random r = new Random();
    for (int y = 0; y < matrix.GetLength(0); y++) {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            double distance = (center - new Vector(x, y)).Length;
            if (distance < radius) {
                matrix[x, y] = r.NextDouble() > 0.5;
            }
        }
    }

}

private void drawMatrix(Vector centerPoint, double radius, bool[,] matrix) {
    var g = this.CreateGraphics();

    Bitmap pixel = new Bitmap(1,1);
    pixel.SetPixel(0, 0, Color.Black);

    for (int y = 0; y < matrix.GetLength(0); y++)
    {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            if (matrix[x, y]) {
                g.DrawImage(pixel, new PointF((float)(centerPoint.X - radius + x), (float)(centerPoint.Y - radius + y)));
            }
        }
    }

    g.Dispose();
}

private void button1_Click(object sender, EventArgs e)
{
    System.Drawing.Rectangle r = new System.Drawing.Rectangle(100,100,200,200);
    double radius = r.Width / 2;
    Vector center = new Vector(r.Left + radius, r.Top + radius);
    Vector normalizedCenter = new Vector(radius, radius);
    bool[,] matrix = getMatrix(r);
    fillMatrix(ref matrix, normalizedCenter);
    drawMatrix(center, radius, matrix);
}

введіть тут опис зображення


3
Поширення не є "досить випадковими". Вони або є, або не є випадковими для даного визначення випадкового. Ваша відповідь є косою: ви не коментуєте свій код і не пояснюєте, як до нього дійшли. Косі відповіді важко дотримуватися і важче довіряти.
Річард

1

Елементом області в колі є dA = rdr * dphi. Цей додатковий фактор r зруйнував вашу ідею випадковим чином вибрати ар та фі. У той час як фіг розподіляється рівним, r - це не, а плоский в 1 / r (тобто ви, швидше за все, потрапите на межу, ніж "око бика").

Отже, щоб генерувати точки, рівномірно розподілені по колу, виберіть phi з плоского розподілу, а r - з розподілу 1 / r.

В якості альтернативи використовуйте метод Монте-Карло, запропонований Мехрдадом.

EDIT

Щоб вибрати випадкову r площину в 1 / r, ви можете вибрати випадковий х з інтервалу [1 / R, нескінченність] та обчислити r = 1 / x. r розподіляється плоско в 1 / r.

Для обчислення випадкової phi виберіть випадковий х з інтервалу [0, 1] та обчисліть phi = 2 * pi * x.


Як саме я можу вибрати r із "розподілу 1 / r" ?
aioobe

0

Я не знаю, чи все-таки це питання відкрите для нового рішення з усіма відповідями, що вже були даними, але я, мабуть, зіткнувся саме з таким самим питанням. Я намагався «міркувати» з собою на рішення, і знайшов його. Це може бути те саме, що дехто вже запропонував тут, але все одно тут:

для того, щоб два елементи поверхні кола були рівними, вважаючи рівними dr, ми повинні мати dtheta1 / dtheta2 = r2 / r1. Запис вираження ймовірності для цього елемента як P (r, theta) = P {r1 <r <r1 + dr, theta1 <theta <theta + dtheta1} = f (r, theta) * dr * dtheta1 та встановлення двох ймовірності (для r1 і r2) рівні, доходимо до (при r і тета незалежні) f (r1) / r1 = f (r2) / r2 = константа, що дає f (r) = c * r. А решта, визначаючи константу c, випливає з умови, що f (r) є PDF.


Цікавий підхід для початку з dtheta1 / dtheta2 = r2 / r1. Не могли б ви детальніше розповісти, як ви придумали це рівняння?
aioobe

Як згадували інші (наприклад, наприклад), диференціальний елемент поверхні кола задається як r dr dtheta, тож якщо припустити, що r1 = r2, тоді у нас буде dr1 * dtheta1 = dr2 * dtheta2, а решта випливає .
arsaKasra

0

Рішення програміста:

  • Створіть бітну карту (матрицю булевих значень). Вона може бути такою великою, як вам хочеться.
  • Намалюйте коло на цій бітній карті.
  • Створіть таблицю пошуку точок кола.
  • Виберіть випадковий індекс у цій таблиці пошуку.
const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

bool matrix[MATRIX_SIZE][MATRIX_SIZE] = {0};

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        matrix[x][y] = true;

        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;

      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()

Растрові карти потрібні лише для пояснення логіки. Це код без растрової карти:

const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;
      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()

0

Я все ще не впевнений у точному "(2 / R2) × r", але очевидно, що кількість точок, необхідних для розподілу в заданій одиниці "dr", тобто збільшення r буде пропорційним r2, а не r.

перевірте таким чином ... кількість точок під деяким кутом тети та між r (0,1r до 0,2r), тобто частка r і кількість точок між r (0,6r до 0,7r) буде дорівнює, якщо ви використовуєте стандартне покоління, оскільки різниця становить лише 0,1р між двома інтервалами. але оскільки площа, що охоплюється між точками (від 0,6 до 0, 0), буде значно більшою, ніж площа, що охоплюється від 0,1 до 0,2 до, однакова кількість балів буде дещо розташована на більшій площі, це я припускаю, що ви вже знаєте, тож функція для генерації випадкових точок не повинно бути лінійним, а квадратичним (оскільки кількість точок, необхідних для розподілу в заданій одиниці 'dr', тобто збільшення r буде пропорційним r2, а не r), тому в цьому випадку це буде обернено квадратичний, оскільки у нас є дельта (0.


Ви перший, хто посилається тут на теорему Піфагора. Я хотів би, якби ви могли розширити це цифрою або двома, підтримуючи своє пояснення. Мені важко слідкувати за тим, як зараз :-(
aioobe

@aioobe Я спробував перефразовувати відповідь, я можу додати схеми, якщо вам потрібно :)
cheesefest

Я розумію, чому я не можу поширити це лінійно. Що я тут не розумію - це зв'язок з Піфагором або з гріхом / cos. Можливо, діаграми могли б мені тут допомогти.
aioobe

Піфагор - це моя помилка, будь ласка, забудь про це, але сподіваюся, ти зрозумів квадратичний характер функції, точний (2 / R2) × r потребує доказів, і я не можу придумати жодного підтвердження цього
cheesefest

0

Така весела проблема.
Обґрунтування ймовірності вибору точки, яка зменшується у міру збільшення відстані від початку осі, пояснюється багаторазово вище. Ми це враховуємо, беручи корінь U [0,1]. Ось загальне рішення для позитивного r у Python 3.

import numpy
import math
import matplotlib.pyplot as plt

def sq_point_in_circle(r):
    """
    Generate a random point in an r radius circle 
    centered around the start of the axis
    """

    t = 2*math.pi*numpy.random.uniform()
    R = (numpy.random.uniform(0,1) ** 0.5) * r

    return(R*math.cos(t), R*math.sin(t))

R = 200 # Radius
N = 1000 # Samples

points = numpy.array([sq_point_in_circle(R) for i in range(N)])
plt.scatter(points[:, 0], points[:,1])

введіть тут опис зображення


0

Ви також можете використовувати свою інтуїцію.

Площа кола - це pi*r^2

Для r=1

Це дає нам площу pi. Припустимо, що у нас є якась функція, fяка б рівномірно розподіляла N=10точки всередині кола. Співвідношення тут таке10 / pi

Тепер ми подвоюємо площу та кількість балів

Для r=2іN=20

Це дає площу 4piі співвідношення зараз 20/4piабо 10/2pi. Коефіцієнт стане меншим і меншим, чим більший радіус, тому що його зростання квадратичний, а Nмасштаби лінійно.

Щоб виправити це, ми можемо просто сказати

x = r^2
sqrt(x) = r

Якщо ви генеруєте вектор у таких полярних координатах

length = random_0_1();
angle = random_0_2pi();

Більше центру приземлиться навколо центру.

length = sqrt(random_0_1());
angle = random_0_2pi();

length більше не є рівномірно розподіленим, але вектор тепер буде рівномірно розподілений.


-1

1) Виберіть випадковий X між -1 та 1.

var X:Number = Math.random() * 2 - 1;

2) Використовуючи формулу кола, обчисліть максимальні та мінімальні значення Y, враховуючи, що X і радіус 1:

var YMin:Number = -Math.sqrt(1 - X * X);
var YMax:Number = Math.sqrt(1 - X * X);

3) Виберіть випадковий Y між цими крайностями:

var Y:Number = Math.random() * (YMax - YMin) + YMin;

4) Включіть значення кінцевого значення та радіус у кінцеве значення:

var finalX:Number = X * radius + pos.x;
var finalY:Number = Y * radois + pos.y;

2
Не рівномірна - ймовірність для [-1, 0] набагато вища, ніж для [0, 0], враховуючи, що р ([- 1, У]) = р ([0, У]), і існує лише одиниця вибір для [-1, Y] та безліч варіантів для [0, Y].
Амадан

Це рішення надає перевагу точкам у лівій та правій частині кола. Точки з х, близьким до нуля, недостатньо представлені. Зовсім не рівномірний розподіл.
Dawood ibn Kareem
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.