Точка (x, y) находится в радиусе, указанном x 2 + y 2 ≤r 2 .Мы можем вычислить количество координат для фиксированного y -значения как:
n y = 1 + 2 × ⌊√ (r 2 -y 2 ) ⌋
Если мы затем нарежем y между 0 и r , и мы считаем каждый n y для y> 0 дважды, мы получаем общее число, поэтому мы можем вычислить это как:
import numpy as np
from math import floor
def total(radius):
r0 = floor(radius)
ys = np.arange(1, r0+1)
halves = 2 * np.sum(2*np.floor(np.sqrt(radius * radius - ys * ys)) + 1)
return halves + 1 + 2 * r0
Таким образом, мы рассчитываем для каждого «слоя» количество интегральных координат и удваиваем каждый слой, так как существует «слой» с таким же количеством интегральных координат в противоположном направлении.,Затем мы добавляем число координат с y = 0 , которое равно 1 + 2 × ⌋r⌋ .
Таким образом, вышеприведенное работает в O (r) с r радиусом круга.
Пример вывода:
>>> total(0)
1.0
>>> total(0.1)
1.0
>>> total(1)
5.0
>>> total(1.1)
5.0
>>> total(1.42)
9.0
>>> total(2)
13.0
>>> total(3)
29.0
Более медленная альтернатива в O (r 2) - это создание сетки, а затем массовое сравнение с ней, например:
import numpy as np
from math import floor
def total_slow(radius):
r0 = floor(radius)
xs = np.arange(-r0, r0+1)
ys = xs[:, None]
return np.sum(xs*xs+ys*ys <= radius*radius)
Вышеприведенное, однако, полезно, если мы хотим убедиться, что наше решение работает.Например:
>>> total_slow(0)
1
>>> total_slow(1)
5
>>> total_slow(2)
13
>>> total_slow(3)
29
дает те же результаты, но мы можем использовать это, чтобы убедиться, что он всегда дает один и тот же результат для большого числа радиусов, например:
>>> [total(r) == total_slow(r) for r in np.arange(0, 10, 0.03)]
[True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True]
Таким образом, это означает, что мы убедились, что оба сгенерировали один и тот же результат для 0
, 0.03
, 0.06
и т. Д. До 10
.Вышеприведенное, конечно, не является формальным доказательством правильности, но оно дает нам некоторые эмпирических свидетельств.
Производительность
Мы можем проверить производительность с помощью timeit
модуль, и мы проверили алгоритмы с тремя радиусами, каждый эксперимент был повторен 10'000 раз:
>>> timeit(partial(total, 1.23), number=10000)
0.11901686200144468
>>> timeit(partial(total, 12.3), number=10000)
0.1255619800031127
>>> timeit(partial(total, 123), number=10000)
0.1318465179974737
>>> timeit(partial(total_slow, 1.23), number=10000)
0.11859546599953319
>>> timeit(partial(total_slow, 12.3), number=10000)
0.15540562200112618
>>> timeit(partial(total_slow, 123), number=10000)
1.3335393390007084
>>> timeit(partial(total_slow, 1.23), number=10000)
0.11859546599953319
>>> timeit(partial(total_slow, 12.3), number=10000)
0.15540562200112618
>>> timeit(partial(total_slow, 123), number=10000)
1.3335393390007084
>>> timeit(partial(points, 1), number=10000)
0.1152820099996461
>>> timeit(partial(points, 12), number=10000)
3.7115225509987795
>>> timeit(partial(points, 123), number=10000)
433.3227958699972
С points
метод @ ShlomiF , мы здесь используем целые числа, поскольку для радиуса с числом с плавающей запятой, этот метод будет давать неверные результаты.
Таким образом, мы получаем следующую таблицу:
radius total total_slow points
1.23 0.119 0.119 0.115*
12.3 0.125 0.155 3.711*
123. 0.131 1.334 433.323*
* with integral radiuses
Это ожидаемое поведение, если принять сложность временисчет: в конечном итоге линейный подход превзойдет квадратичный подход.