Crear un número aleatorio dentro de un anillo

Estoy intentando generar un número aleatorio que esté dentro de un anillo, es decir, tenemos un radio máximo y mínimo. Intenté hacer:

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

Pero esto es muy lento. ¿Es posible introducir más random.uniform en random.uniform o hay otro método?

En general, puede dibujar la distribución correcta directamente o usar el rechazo.

Para dibujar directamente usar

  • Dibuje theta uniformemente en [0,2pi): theta = random.uniform(0,2*pi)
  • extrae r de la distribución de la ley de poder r ^ 1 .

    La única complejidad en comparación con hacer esto para un círculo es que el PDF se ejecuta desde [r_min, r_max] no [0, r_max]. Esto lleva a

    CDF = A \ int_ {r_min} ^ {r} r ‘dr’ = A (r ^ 2 – r_min ^ 2) / 2

    para A la constante de normalización

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

    implicando que

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

    y se puede simplificar un poco.

  • luego calcule (x, y) por la transformación usual de coordenadas radiales
    x = r * cos(theta)
    y = r * sin(theta)

Este método de integración de PDF, normalización de CDF e inversión es general y, en ocasiones, se denomina “Teorema fundamental del muestreo”.

Rechazo

Dibuje (x, y) en una caja lo suficientemente grande como para contener el anillo, luego rechace todos los casos donde `r = sqrt (x x + y y) exceda de r_max o sea menor que r_min.

Esto es razonablemente eficiente si el orificio en el medio es pequeño y muy ineficiente si el orificio es grande.

El método que está utilizando debería funcionar bastante eficientemente para un anillo grueso (donde r1 <<< r2). Si, en cambio, está tratando con un anillo estrecho (r2 - r1 <<< r1), puede usar algo como esto en su lugar:

 r = random.uniform(r1, r2) theta = random.uniform(0, 2 * PI) x = r * math.sin(theta) y = r * math.cos(theta) 

Tenga en cuenta que esto proporciona resultados levemente no uniformes (hay una distribución constante de puntos por unidad de ángulo, no por unidad de área).