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

我意识到,只要在区间[0…2π),且在区间(0…R)我最终会有更多的点指向中心,因为对于两个给定的半径,小半径内的点会比大半径内的点彼此更接近。

我在这里找到了一篇关于这个的博客文章,但我不明白他的推理。我认为这是正确的,但我真的很想知道他从哪里得到(2/R2)×r以及他如何得到最终解。


更新:在发布这个问题7年之后,关于平方根算法背后的数学问题,我仍然没有得到一个令人满意的答案。所以我花了一天时间自己写了一个答案。链接到我的答案。


当前回答

这可能会帮助那些对选择速度算法感兴趣的人;最快的方法是(可能?)拒绝抽样。

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

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

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

其他回答

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

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

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

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

这就得到了圆盘上均匀的点分布。

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

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

这取决于你对"均匀随机"的定义。这是一个微妙的点,你可以在这里的wiki页面上阅读更多关于它的内容:http://en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29,在这里同样的问题,对“均匀随机”给出不同的解释会给出不同的答案!

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

It seems like the blog entry is trying to make it uniformly random in the following sense: If you take a sub-circle of the circle, with the same center, then the probability that the point falls in that region is proportional to the area of the region. That, I believe, is attempting to follow the now standard interpretation of 'uniformly random' for 2D regions with areas defined on them: probability of a point falling in any region (with area well defined) is proportional to the area of that region.

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;