在环形区域内生成随机数

10 投票
1 回答
4140 浏览
提问于 2025-04-17 11:18

我想生成一个在环形区域内的随机数,也就是说,我们有一个最大半径和一个最小半径。我试着这样做:

while True:
    x=random.uniform(-maxR, maxR)
    y=random.uniform(-maxR, maxR)
    R=math.sqrt(x**2 + y**2)
    if R <= maxRadius and R >= minRadius:
        if x>= -maxRadius and x <= maxRadius and x<=-minRadius and x>= minRadius:
            print "passed x"
            if y>= -maxRadius and y <= maxRadius and y<=-minRadius and y>= minRadius: 
                break

但是这样做速度很慢。有没有办法给random.uniform添加更多的限制条件,或者有没有其他的方法?

1 个回答

24

一般来说,你可以直接绘制正确的分布,或者使用拒绝采样的方法。

直接绘制的方法

  • 在区间 [0,2pi) 上均匀地生成一个角度 theta:theta = random.uniform(0,2*pi)
  • 幂律分布 r^1中生成 r。

    与在圆上进行这项操作相比,唯一的复杂之处在于你的概率密度函数(PDF)是从 [r_min,r_max] 而不是 [0,r_max]。这导致了:

    累积分布函数(CDF) = A \int_{r_min}^{r} r' dr' = A (r^2 - r_min^2)/2

    这里的 A 是归一化常数。

    A = 2/(r_max*r_max - r_min*r_min)
    

    这意味着:

    r = sqrt(2*random.uniform(0,1)/A + r_min*r_min)
    

    你可以稍微简化一下。

  • 然后通过常规的极坐标转换计算 (x,y):
    x = r * cos(theta)
    y = r * sin(theta)

这种积分 PDF、归一化 CDF 和反转的方法是通用的,有时被称为“采样的基本定理”。

拒绝采样

在一个足够大的框中绘制 (x,y),这个框要能包含环形区域,然后拒绝所有那些 `r = sqrt(xx + yy)` 超过 r_max 或小于 r_min 的情况。

如果中间的空洞很小,这种方法效率还算合理;但如果空洞很大,那就非常低效了。

撰写回答