【问题标题】:Generate a random point within a circle (uniformly)在圆内生成一个随机点(均匀)
【发布时间】:2011-08-15 19:20:25
【问题描述】:

我需要在半径R的圆内生成一个均匀随机的点。

我意识到,只要在区间 [0 ... 2π) 中选择一个均匀随机的角度,在区间 (0 ... R) 中选择一个均匀随机的半径,我最终会得到更多的点朝向中心,因为对于两个给定的半径,较小半径中的点将比较大半径中的点更靠近彼此。

我在over here 上找到了一篇博客文章,但我不明白他的推理。我想这是正确的,但我真的很想了解他从哪里得到 (2/R2r 和他是如何得出最终解决方案的。


更新:在发布此问题 7 年后,我仍然没有收到关于平方根算法背后数学的实际问题的满意答案。所以我花了一天时间自己写一个答案。 Link to my answer.

【问题讨论】:

  • 拒绝抽样的缺点真的很大吗?所需的预期尝试次数为 4/π ≈ 1.27,您需要超过 k 次尝试的概率为 (1-π/4)^k。对于k=20,这是 ≈ .00000000000004,对于 k=50,它大约是 10^{-34}。您可以随时接受这些赔率;你会没事的。
  • 其实拒绝抽样确实提供了终止的保证。您的算法永远不会终止的可能性非常低(准确地说为零)。
  • @spex 在实践中,拒绝技术更快,因为它避免了超越函数评估的需要。
  • 我想对速度差异进行一些测试,所以我实现了 sigfpe 和 btilly 推荐的方法,以及简单的拒绝技术。在 c# 中运行(使用带有恒定种子的 System.Random)我 10m 点的时间是 sigfpe: 1.17s btilly: 1.12s
  • (续)拒绝:0.52s 所有都给出了相同的平均值和标准偏差(至 3 sig. fig)。正如预期的那样,拒绝抽样的失败率为 27%(4/pi-1),因此需要的随机数比 btilly 多 27%,但比 sigfpe 少 15%。这证实了 pjs 和其他人制作的 cmets 拒绝抽样可能是最好的方法,除非随机数的生成成本非常高。

标签: math random geometry probability


【解决方案1】:

如何在半径为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线性增长时间>。换句话说,所需的probability density function (PDF) 呈线性增长。由于 PDF 的面积应该等于 1,最大半径是 1,所以我们有


所以我们知道我们的随机值的期望密度应该是什么样子。 现在:当我们只有一个介于 0 和 1 之间的均匀随机值时,我们如何生成这样一个随机值?

我们使用了一个叫做inverse transform sampling的技巧

  1. 从 PDF 创建 cumulative distribution function (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 等于 2x 的随机半径值。

第 1 步:创建 CDF:

由于我们使用的是实数,因此 CDF 表示为 PDF 的积分。

CDF(x) = ∫ 2x = x2

第 2 步:沿 y = x 镜像 CDF:

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

CDF:     y = x2
交换:   x = y2
求解:y = √x
CDF-1y = √x

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

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

这是我们打算推导出来的 :-)

【讨论】:

  • 在擂台上?像固定半径一样?不知道我是否理解你的问题,但如果你有一个固定的半径,你只需要随机化角度。
  • 我尝试使用更简单的单词“Ring”而不是 Annulus - 由两个同心圆包围的区域。在这种情况下,拒绝算法变得无效,并且第一个顶级算法很难推广。您的算法也涵盖了具有一个半径的极端情况。我们总是生成半径为 sqrt(random(min_radius^2, max_radius^2)) 即使 min_radius==max_radius。
  • 哦,太好了!需要明确的是,当你说random(min_radius², max_radius²) 时,你的意思是不是等同于random() * (max_radius² - min_radius²) + min_radius²,其中random() 返回一个介于0 和1 之间的统一值?
  • 是的,这正是我的意思:半径 = sqrt(random() * (max_radius² - min_radius²) + min_radius²)。
  • 用来创建戒指,它的工作codepen.io/KonradLinkowski/pen/ExjLGxJ
【解决方案2】:

让我们像阿基米德那样处理这个问题。

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

现在考虑一个圆圈。在极限中,我们可以将其视为无限多的等腰三角形 ABC,其原点为 B,圆周上的 A 和 C 彼此几乎消失。我们可以简单地通过选择角度 theta 来选择其中一个三角形。所以我们现在需要通过在长条 ABC 中选择一个点来生成到中心的距离。再次延伸到 ABCD,其中 D 现在是圆心半径的两倍。

使用上述方法很容易在 ABCD 中选择一个随机点。在 AB 上随机选取一个点。在 BC 上统一选择一个随机点。 IE。在 [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]

【讨论】:

  • @Karelzarath 我喜欢一个无限薄三角形的反直觉概念,它的一端比另一端更宽 :-) 它得到了正确的答案。
  • @hammar 不确定它是否可以很好地推广到 n 维。但是对于 3d,您可以使用阿基米德的另一个结果!使用“帽子盒”定理在圆柱体上生成一个点(简单!),然后将其映射回球体。这给出了一个方向。现在将random()+random()+random() 与一些更复杂的折叠一起使用(即,将无限薄平行六面体折叠成四面体)。虽然不相信这是一个好方法。
  • 我想 1 分钟来弄清楚 random()+random() 和 2*random() 之间的区别...我太愚蠢了:/
  • @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 左右,这是错误的。
  • @Tharwen 尝试使用这两种方案来生成随机数,看看你会得到什么。 2*random() 给出均匀分布在 0 到 2 范围内的数字。 random()+random() 给出 0 到 2 范围内的数字,但(通常)1.0 附近的数字比 0.0 或 2.0 附近的数字多。这就像掷两个骰子和相加比任何其他数字更有可能得到 7。
【解决方案3】:

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

在 (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 的圆内
  • 谢谢,这是你的 Java 代码,也许有人会觉得它有用:float random1 = MathUtils.random();浮动随机2 = MathUtils.random(); float randomXPoint = random2*radiusMathUtils.cos(MathUtils.PI2*random1/random2); float randomYPoint = random2*radiusMathUtils.sin(MathUtils.PI2*random1/random2);
  • 非常好!我喜欢更多概率集中积分的想法,所以如果我们在b < a 时不交换,我们可以实现这一点!例如在javascript中jsfiddle.net/b0sb5ogL/1
  • 我认为您的解决方案很糟糕。它没有给出统一的结果。检查此屏幕截图prntscr.com/fizxgc
  • 你能解释一下如何切割圆并拉直吗?
【解决方案4】:

注意点密度与半径的平方成反比,因此不要从[0, r_max] 中选择r,而是从[0, r_max^2] 中选择,然后将坐标计算为:

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

这将为您在磁盘上提供均匀的点分布。

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

【讨论】:

    【解决方案5】:

    这样想。如果您有一个矩形,其中一个轴是半径,一个轴是角度,并且您在该矩形内取半径 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 应该映射到 r = R。此外,它通过平方根函数,这很有意义并匹配链接。

    【讨论】:

      【解决方案6】:

      朴素解决方案不起作用的原因是它为靠近圆心的点提供了更高的概率密度。换句话说,半径为 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。因此,您应该给圆 r 一个等于 (2 * pi * r) / (pi * R^2) = 2 * r/R^2 的概率。这更容易理解,也更直观,但在数学上并不那么合理。

      【讨论】:

        【解决方案7】:

        设ρ(半径)和φ(方位角)是两个随机变量,对应于圆内任意点的极坐标。如果点是均匀分布的,那么ρ和φ的分布函数是什么?

        对于任意 r: 0

        P[ρ 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)

        从 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)
        

        你会得到

        【讨论】:

          【解决方案8】:

          这真的取决于你所说的“均匀随机”是什么意思。这是一个微妙的点,您可以在此处的 wiki 页面上阅读更多相关信息:http://en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29,同样的问题,对“均匀随机”给出不同的解释会给出不同的答案!

          根据您选择点的方式,分布可能会有所不同,即使它们在某些意义上是均匀随机的。

          似乎博客条目试图在以下意义上使其均匀随机:如果你取圆的一个子圆,具有相同的中心,那么该点落在该区域的概率与该地区的面积。我相信,这是试图遵循现在对带有areas defined on them 的 2D 区域的“均匀随机”的标准解释:点落在任何区域(具有明确定义的区域)的概率与该区域的面积成正比。

          【讨论】:

          • 或者更确切地说,该点落入任意个任意区域的概率与该区域的面积成正比——假设区域has an area
          • @Shree:正确,这就是我在括号中的陈述所暗示的意思。我会说清楚的,谢谢。顺便说一句,关于博客,没有真正的证据表明任意区域给出成比例的概率,因此我选择这样表述。
          【解决方案9】:

          这是我的 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()
          

          【讨论】:

          • 为什么不只是r = np.sqrt(np.random.uniform(0.0, rad**2, num))
          【解决方案10】:

          我认为在这种情况下,使用极坐标是一种使问题复杂化的方法,如果您将随机点选入边长为 2R 的正方形中,然后选择点 (x,y) 这样 @987654322 会容易得多@。

          【讨论】:

          • 你的意思是 x^2+y^2
          • 这是拒绝抽样。没关系,但确实意味着计算时间会有所不同,这可能是个问题。
          • 所有正方形都是 4 面的。
          • 这个算法比任何涉及平方根或 sin/cos 计算的算法都更有效。它拒绝了少于 21.5% 的正方形点。
          【解决方案11】:

          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);
          }
          

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

          【讨论】:

            【解决方案12】:

            首先我们生成一个 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] ]
            

            我们现在可以用 0 到 1 之间的随机数替换 cdf

            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 度}

            【讨论】:

            • "我们现在可以用 0 到 1 的随机数替换 cdf"。为什么你可以这样做?
            【解决方案13】:

            我用过一次这个方法: 这可能是完全未优化的(即它使用点数组,因此无法用于大圆圈),但提供了足够的随机分布。如果您愿意,您可以跳过矩阵的创建并直接绘制。方法是随机化一个矩形中落在圆内的所有点。

            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);
            }
            

            【讨论】:

            • 分布不够“随机”。对于给定的随机定义,它们要么是随机的,要么不是随机的。你的回答是倾斜的:你没有评论你的代码,也没有解释你是如何得到它的。间接的答案很难理解,也更难相信。
            【解决方案14】:

            圆中的面积元素是dA=rdr*dphi。那个额外的因素 r 破坏了你随机选择 r 和 phi 的想法。虽然 phi 是平分布的,但 r 不是,而是 1/r 平分布(即,您比“靶心”更有可能触及边界)。

            所以要生成均匀分布在圆上的点,从平面分布中选择 phi,从 1/r 分布中选择 r。

            或者使用 Mehrdad 提出的 Monte Carlo 方法。

            编辑

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

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

            【讨论】:

            • 我究竟如何从"a 1/r distribution"中挑选一个r
            【解决方案15】:

            你也可以运用你的直觉。

            圆的面积是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 不再均匀分布,但向量现在将均匀分布。

            【讨论】:

              【解决方案16】:

              半径与“接近”该半径的点数之间存在线性关系,因此他需要使用半径分布,该半径分布也使得半径r 附近的数据点数与r 成正比.

              【讨论】:

                【解决方案17】:

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

                为了使圆表面的两个元素相等,假设 dr 相等,我们必须有 dtheta1/dtheta2 = r2/r1。将该元素的概率表达式写为 P(r, theta) = P{ r1

                【讨论】:

                • 从 dtheta1/dtheta2 = r2/r1 开始的有趣方法。你能详细说明你是如何得出这个等式的吗?
                • 正如其他人提到的(例如,鸣喇叭),圆的表面的微分元素被给出为 rdrdtheta,所以如果我们假设 r1 = r2,然后我们将有 dr1*dtheta1 = dr2*dtheta2 其余的如下。
                【解决方案18】:

                我仍然不确定确切的“(2/R2)×r”,但显而易见的是需要在给定单位“dr”中分布的点数,即 r 的增加将与 r2 成正比,而不是河。

                以这种方式检查...在某个角度 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),所以在这种情况下,它将与二次的,因为我们在两个区间中的 delta (0.1r) 必须是某个函数的平方,所以它可以作为点的线性生成的种子值(因为后记,这个种子在 sin 和 cos 函数中线性使用),所以我们知道,dr 必须是二次值,并且要使这个种子二次,我们需要从 r 的平方根而不是 r 本身得出这个值,我希望这能更清楚一点。

                【讨论】:

                • 你是第一个在这里引用毕达哥拉斯定理的人。如果你能用一两个数字来扩展它,我会很高兴,支持你的解释。我现在很难跟上:-(
                • @aioobe 我试图改写答案,如果你需要我可以添加图表:)
                • 我明白为什么我不能将它线性展开。我在这里不明白的是与毕达哥拉斯或 sin/cos 的联系。也许图表可以在这里帮助我。
                • 毕达哥拉斯是我的错误,请忘记它,但希望你理解函数的二次性质,确切的 (2/R2)×r 需要证明,我无法为此提供任何证明
                【解决方案19】:

                真是个有趣的问题。
                上面多次解释了随着与轴原点的距离增加而选择点的概率降低的基本原理。我们通过取 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])
                

                【讨论】:

                  【解决方案20】:

                  这可能有助于有兴趣选择速度算法的人;最快的方法是(可能?)拒绝抽样。

                  只需在单位正方形内生成一个点并拒绝它,直到它在一个圆圈内。例如(伪代码),

                  def sample(r=1):
                      while True:
                          x = random(-1, 1)
                          y = random(-1, 1)
                          if x*x + y*y <= 1:
                              return (x, y) * r
                  

                  虽然它有时可能运行不止一次或两次(而且它不是恒定时间或适合并行执行),但它的速度要快得多,因为它不使用像 sincos 这样的复杂公式。

                  【讨论】:

                  • 我认为它没有被建议,因为它没有回答问题。
                  • 你是对的,但问题来自搜索“圈内的随机点” - 考虑到问题的受欢迎程度,它可能对其他人有用。
                  • 对,我只是在回答 “我不知道为什么还没有建议” 部分。顺便说一句,如果您专注于执行速度,您可以拨打sqrt(...)。 (sqrt(x) 将是 &lt;= 1 当且仅当 x&lt;= 1
                  • 是的,你在这两个帐户上都是对的。我真的怀疑自己一秒钟,因为 wolfram alpha 说他们不平等(已经很晚了)
                  【解决方案21】:

                  程序员解决方案:

                  • 创建位图(布尔值矩阵)。它可以任意大。
                  • 在该位图中画一个圆圈。
                  • 创建圆点的查找表。
                  • 在此查找表中选择一个随机索引。
                  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];
                  } // ()
                  

                  【讨论】:

                    【解决方案22】:

                    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;
                    

                    【讨论】:

                    • 不统一 - [-1, 0] 的概率远高于 [0, 0],假设 p([-1, Y]) = p([0, Y] ),[-1, Y]只有一个选择,[0, Y]有很多选择。
                    • 这个解决方案有利于圆的左侧和右侧的点。 x 接近于零的点代表不足。根本不是均匀分布。
                    猜你喜欢
                    • 2012-10-15
                    • 2013-05-12
                    • 2019-08-15
                    • 2020-09-14
                    • 2010-09-22
                    相关资源
                    最近更新 更多