Создание случайного числа в кольцевом пространстве

Я пытаюсь создать случайное число, которое находится внутри кольца, то есть мы имеем максимальный и минимальный радиус. Я пробовал:

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

В общем, вы можете либо прямо направить правильное распределение, либо отказаться от него.

Для прямого использования

  • равномерно нарисовать theta на [0,2pi): theta = random.uniform(0,2*pi)
  • извлечь r из степенного распределения r ^ 1.

    Единственная сложность по сравнению с этим для круга заключается в том, что 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.

Это разумно эффективно, если отверстие в середине небольшое и очень неэффективно, если отверстие большое.

Ответ 2

Метод, который вы используете, должен работать достаточно эффективно для толстого кольца (где r1 < r2). Если вы имеете дело с узким кольцом (r2 - r1 < < r1), тогда вы можете использовать что-то вроде этого:

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

Заметим, что это дает слегка неравномерные результаты (существует постоянное распределение точек на единичный угол, а не на единицу площади).