我需要在半径为R的圆内生成一个均匀随机点。
我意识到,只要在区间[0…2π),且在区间(0…R)我最终会有更多的点指向中心,因为对于两个给定的半径,小半径内的点会比大半径内的点彼此更接近。
我在这里找到了一篇关于这个的博客文章,但我不明白他的推理。我认为这是正确的,但我真的很想知道他从哪里得到(2/R2)×r以及他如何得到最终解。
更新:在发布这个问题7年之后,关于平方根算法背后的数学问题,我仍然没有得到一个令人满意的答案。所以我花了一天时间自己写了一个答案。链接到我的答案。
我需要在半径为R的圆内生成一个均匀随机点。
我意识到,只要在区间[0…2π),且在区间(0…R)我最终会有更多的点指向中心,因为对于两个给定的半径,小半径内的点会比大半径内的点彼此更接近。
我在这里找到了一篇关于这个的博客文章,但我不明白他的推理。我认为这是正确的,但我真的很想知道他从哪里得到(2/R2)×r以及他如何得到最终解。
更新:在发布这个问题7年之后,关于平方根算法背后的数学问题,我仍然没有得到一个令人满意的答案。所以我花了一天时间自己写了一个答案。链接到我的答案。
当前回答
你也可以用你的直觉。
圆的面积是*r^2
为r = 1
得到的面积是。让我们假设我们有某种函数f,它将N=10个点均匀分布在一个圆内。这个比值是10 /
现在我们把面积和点数翻倍
对于r=2和N=20
面积是4,比值是20/4或10/2。半径越大,比值就越小,因为它的增长是二次的,N是线性的。
为了解决这个问题,我们可以说
x = r^2
sqrt(x) = r
如果在极坐标下生成一个向量
length = random_0_1();
angle = random_0_2pi();
更多的点会落在中心周围。
length = sqrt(random_0_1());
angle = random_0_2pi();
长度不再是均匀分布的,但是向量现在是均匀分布的。
其他回答
圆中的面积元是dA=rdr*dphi。这个额外的因子r破坏了你随机选择r和的想法。虽然phi分布平坦,但r不是,而是在1/r内平坦(也就是说,你更有可能击中边界而不是“靶心”)。
为了生成在圆上均匀分布的点从平面分布中选取r从1/r分布中选取。
或者使用Mehrdad提出的蒙特卡罗方法。
EDIT
要在1/r中选择一个随机的r,你可以从区间[1/ r,无穷]中选择一个随机的x,并计算r=1/x。R以1/ R为单位平坦分布。
为了计算一个随机的,从区间[0,1]中选择一个随机的x,并计算=2*pi*x。
下面是我的Python代码,从半径为rad的圆中生成num个随机点:
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()
这样想。如果你有一个矩形,其中一个轴是半径,一个是角,你取这个矩形内半径为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
好,这就是如何得到链接中的公式。
然后,最后一部分是从(0,1)中的均匀随机变量u你必须从这个期望密度f(r)映射到累积分布函数的逆函数。要理解为什么会这样,你可能需要找到像Papoulis这样的高级概率文本(或者自己推导)。
对f(r)积分得到f(r) = r^2/ r^2
为了求出它的反函数你设u = r^2/ r^2然后解出r,得到r = r *√(u)
直观上讲,u = 0映射到r = 0。同样,u = 1应该映射到r = r。同样,它通过平方根函数,这是有意义的,与链接匹配。
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);
}
基于以前的解决方案https://stackoverflow.com/a/5838055/5224246从@sigfpe
让我们像阿基米德那样处理这个问题。
我们如何在三角形ABC中均匀地生成一个点,其中|AB|=|BC|?让我们把它扩展到平行四边形ABCD。在ABCD中很容易均匀地生成点。我们均匀地选择AB上的X点和BC上的Y点并选择Z使XBYZ是一个平行四边形。为了在原始三角形中得到一个均匀选择的点,我们只需将ADC中出现的任何点沿AC折叠回ABC。
现在考虑一个圆。在极限情况下,我们可以把它想象成无穷多个等腰三角形ABC, B在原点,A和C在周长上,彼此逐渐接近。我们可以从这些三角形中选择一个角。所以我们现在需要通过在ABC条上选择一点来生成到中心的距离。同样,延伸到ABCD, D现在是圆中心半径的两倍。
使用上述方法可以很容易地在ABCD中选择一个随机点。在AB上随机选一个点,在BC上随机选一个点。Ie。在[0,R]上取一对随机数字x和y,给出离中心的距离。三角形是一条细条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]