在圆内均匀地生成一个随机点


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 2011年

3
实际上,拒收抽样确实为终止提供了保证。算法永远不会终止的几率极低(准确地说是零)。
Jared Nielsen

2
在我看来,剔除采样的缺点的重要性与使用避免剔除的采样方法的难易程度成正比。在这种情况下,缺点很重要,因为没有拒绝的采样很简单。
spex 2014年

4
@spex实际上,拒绝技术更快,因为它不需要先验函数评估。
pjs

2
(续)剔除:0.52s全部给出相同的平均值和标准偏差(至3 sig。图)。正如预期的那样,拒绝采样在27%的时间内(4 / pi-1)失败,因此需要比btilly多27%的随机数,但比sigfpe少15%。这证实了pjs和其他人的评论,即拒绝采样可能是最好的方法,除非生成随机数非常昂贵。
彼得·戴维森

Answers:


189

让我们像阿基米德一样进行处理。

如何在| AB | = | BC |的三角形ABC中均匀地生成一个点?让我们通过扩展到平行四边形ABCD来使此过程变得更容易。在ABCD中统一生成点很容易。我们统一选择AB上的随机点X和BC上的Y,然后选择Z,使XBYZ为平行四边形。为了在原始三角形中获得一致选择的点,我们只需将ADC中出现的所有点沿AC折回到ABC。

现在考虑一个圆圈。在极限情况下,我们可以认为它是无限多个等腰三角形ABC,其原点为B,圆周上的A和C几乎彼此消失。我们可以简单地通过选择角度theta来选择这些三角形之一。因此,我们现在需要通过在条状ABC中选取一个点来生成与中心的距离。同样,扩展到ABCD,其中D现在是距圆心半径的两倍。

使用上述方法可以轻松地在ABCD中选择随机点。在AB上随机选择一个点。在BC上均匀地选择一个随机点。就是 均匀地在[0,R]上选择一对随机数x和y,以给出距中心的距离。我们的三角形是细条,所以AB和BC本质上是平行的。因此,点Z只是距原点的距离x + y。如果x + y> R,我们向后折叠。

这是R = 1的完整算法。我希望你同意这很简单。它使用trig,但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 2011年

2
@hammar不确定它能很好地推广到n个维度。但是对于3D,您可以使用阿基米德的另一个结果!使用“帽框”定理在圆柱体上生成一个点(简单!),然后将其映射回球体。这给出了一个方向。现在使用random()+random()+random()一些更复杂的折叠(例如,将无限细的平行六面体与四面体进行6折)。虽然不相信这是一个好方法。
sigfpe 2011年

2
我以为1分钟就能弄清random()+ random()和2 * random()之间的区别……我太傻了:/
JiminP 2011年

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 2012年

2
@Tharwen尝试使用两种方案来生成随机数,然后看看您得到了什么。2 * random()给出在0到2范围内均匀分布的数字。random()+ random()给出在0到2范围内的数字,但是(通常)1.0附近的数字多于0.0或2.0。这就像掷两个骰子并求和比其他任何数字都更有可能产生7。
sigfpe 2012年

132

如何在半径为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(random())。

…因此,回到生成我们的PDF等于2 x的随机半径值。

步骤1:创建CDF:

由于我们正在处理实数,因此CDF表示为PDF的整体。

CDFx)=∫2 x = x 2

步骤2:沿着y = x镜像CDF

从数学上讲,这可以归结为交换xy并求解y

CDF:      ÿ = X 2
交换:    X = ÿ 2
解:    Ý =√ X
CDF -1:   Ý =√ X

步骤3:将结果函数应用于0到1之间的统一值

CDF -1(random())=√random()

这是我们着手得出的:-)


该算法可用于有效地在环上生成点。
伊万·科夫通

在戒指上?喜欢固定半径?不确定我是否理解您的问题,但是如果半径固定,则只需将角度随机化即可。
aioobe '19

2
我尝试使用更简单的单词“ Ring”代替环面-由两个同心圆界定的区域。在这种情况下,拒绝算法变得无效,并且难以归纳出最上层算法。算法也涵盖了具有一个半径的转角情况。即使min_radius == max_radius,我们也总是将半径生成为sqrt(random(min_radius ^ 2,max_radius ^ 2))。
伊万·科夫通

1
不错哦!明确地说,当您说时random(min_radius², max_radius²),您的意思是否等于random() * (max_radius² - min_radius²) + min_radius²,其中random()返回的统一值在0到1之间?
aioobe '19

是的,这正是我的意思:radius = sqrt(random()*(max_radius²-min_radius²)+min_radius²)。
伊万·科夫通

27

这是一个快速简单的解决方案。

选择(0,1)范围内的两个随机数,即ab。如果是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的圆内
Greg Zaal 2014年

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);
Tony Ceralva 2014年

很好!我喜欢将分数集中的可能性更大的想法,因此,如果我们不交换意见,那么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:”。

这里的基本前提是,您可以根据所需概率密度函数的累积分布函数的反函数来映射制服,从而从制服创建具有所需分布的变量。为什么?暂时将其视为理所当然,但这是事实。

这是我对数学的直观解释。相对于r的密度函数f(r)必须与r本身成正比。了解这一事实是任何基础演算书籍的一部分。请参阅有关极区元素的部分。其他一些海报提到了这一点。

所以我们称它为f(r)= C * r;

事实证明这是大部分工作。现在,由于f(r)应该是概率密度,因此您可以轻松地看到,通过在区间(0,R)上积分f(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 * sqrt(u)

这从直觉上也很有意义,u = 0应该映射到r =0。而且,u = 1 shoudl映射到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。因此,您应将圆弧的ra概率设置为等于(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(φ)

无法拒绝为R = 1发布python代码。

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

这实际上取决于您所说的“均匀随机”。这是一个微妙的观点,您可以在以下Wiki页面上阅读有关此问题的更多信息:http : //en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29,其中相同的问题对“均匀随机”给出不同的解释不同的答案!

这取决于你如何选点,分布可能会发生变化,即使他们是在同样的随机一些感觉。

博客条目似乎试图在以下意义上使其均匀一致:如果您以相同的中心为圆的子圆,则该点落入该区域的概率与该区域的比例成正比。该区域。我认为,这是在尝试对在其上定义面积的 2D区域采用“统一随机”的标准解释:点落入任何区域(定义明确的区域)的概率与该区域的面积成正比。


5
或者说,该点落在概率任何任意区域是成正比的区域的面积-假定区域的面积
ShreevatsaR 2011年

@Shree:正确,这是我用括号括起来的意思。我会说得更清楚,谢谢。顺便说一句,关于博客,没有真正的证据证明任意区域给出了比例概率,因此我选择用这种方式表述。

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 2011年

1
这是拒绝采样。可以,但是确实意味着计算时间有所不同,这可能是一个问题。
Steve Bennett

所有正方形均为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点

基于来自@sigfpe的previus解决方案https://stackoverflow.com/a/5838055/5224246


2

首先我们生成一个cdf [x]

点到圆心的距离小于x的概率。假设圆的半径为R。

显然,如果x为零,则cdf [0] = 0

显然,如果x为R,则cdf [R] = 1

显然,如果x = r,则cdf [r] =(Pi r ^ 2)/(Pi R ^ 2)

这是因为圆上的每个“小区域”都具有相同的被拾取概率,因此该概率与所讨论的区域成比例。与圆心的距离为x的面积为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 deg}


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破坏了您随机选择ar和phi的想法。尽管phi是平面分布,但r不是,而是1 / r平坦(即,比“靶心”更有可能击中边界)。

因此,要生成均匀分布在圆上的点,从平面分布中拾取phi,从1 / r分布中获得r。

也可以使用Mehrdad提出的Monte Carlo方法。

编辑

要选择1 / r中的随机r平,您可以从区间[1 / R,无穷大]中选择一个随机x并计算r = 1 / x。然后,r以1 / r均匀分布。

要计算随机phi,请从区间[0,1]中选择一个随机x,然后计算phi = 2 * pi * x。


我如何从“ 1 / r分布”中选择一个r
aioobe 2011年

0

我不知道这个问题是否仍然可以解决所有已经给出答案的新解决方案,但是我碰巧遇到了完全相同的问题。我试图与自己“推理”一个解决方案,然后找到了解决方案。这可能与此处已经提出的建议相同,但无论如何,它是:

为了使圆的曲面的两个元素相等,并假设它们等于dr,必须使dtheta1 / dtheta2 = r2 / r1。将该元素的概率表达式写为P(r,theta)= P {r1 <r <r1 + dr,theta1 <theta <theta + dtheta1} = f(r,theta **** dtheta1概率(对于r1和r2)相等,我们得出(假设r和theta是独立的)f(r1)/ r1 = f(r2)/ r2 =常数,得出f(r)= c * r。其余的,根据f(r)为PDF的条件确定常数c。


从dtheta1 / dtheta2 = r2 / r1开始的有趣方法。您能否详细说明如何提出该方程式?
aioobe 2013年

正如其他人提到的(例如,鸣笛声),圆表面的微分元素为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成正比。

以这种方式检查...在某个角度theta且r之间的点数(0.1r至0.2r),即如果使用标准生成,则r的分数与r之间的点数(0.6r至0.7r)将相等,因为两个间隔之间的差异仅为0.1r。但是由于点之间的覆盖范围(0.6r至0.7r)将比0.1r到0.2r之间覆盖的面积大得多,因此相等的点数将在较大的区域中稀疏地间隔开,这我想您已经知道了,所以该函数生成随机点必须不是线性的而是二次的(因为需要以给定单位“ dr”分配的点数,即r的增加将与r2成正比,而不与r成正比),因此在这种情况下它将与平方,因为我们有增量(0。


您是第一个在此引用毕达哥拉斯定理的人。如果您可以用一个或两个数字来扩展此范围,并支持您的解释,我将不胜感激。我现在很难理解:-(
aioobe

@aioobe我试图改写答案,如果需要的话,我可以添加图表:)
Cheesefest

我知道为什么我不能线性地散布它。我在这里不了解的是与毕达哥拉斯或罪恶/ cos的联系。也许图表可以帮助我。
aioobe

毕达哥拉斯(Pythagoras)是我的错误,请忘记它,但是希望您理解函数的二次性质,确切的(2 / R2)×r需要证明,而我对此无法提供任何证明
Cheesefest

0

这么有趣的问题。
上面多次解释了随着距轴原点的距离增加而选择的点降低的可能性的基本原理。我们通过采用U [0,1]的根来解决这个问题。这是Python 3中正R的一般解决方案。

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=2N=20

给出的面积为4pi,比率现在为20/4pi10/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)在-1和1之间选择一个随机X。

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

2)使用圆公式,计算给定X且半径为1的Y的最大值和最小值:

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
不统一-假设p([-1,Y])= p([0,Y]),并且只有一个,则[-1,0]的概率大大高于[0,0] [-1,Y]的选择和[0,Y]的许多选择。
Amadan 2015年

该解决方案有利于指向圆的左侧和右侧的点。x接近零的点表示不足。根本没有统一的分布。
达伍德·伊本·卡里姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.