Как говорит Википедия : «Современное сито Аткина более сложное, но более быстрое при правильной оптимизации » (мой акцент).
Первое очевидное место, чтобы сэкономить некоторое время в первом наборе циклов, это прекратить итерации по y
, когда 4*x**2 + y**2
больше n
. Например, если n
равно 1 000 000, а x
равно 450, то вам следует прекратить итерацию, когда y
больше 435 (вместо продолжения до 999, как вы делаете в данный момент). Таким образом, вы можете переписать первый цикл как:
for x in (1..Math.sqrt(n/4).truncate)
X = 4 * x ** 2
for y in (1..Math.sqrt(n - X).truncate)
k = X + y ** 2
sieve[k] = !sieve[k] if k%12 == 1 or k%12 == 5
end
end
(Это также позволяет избежать повторного вычисления 4*x**2
каждый раз вокруг цикла, хотя это, вероятно, очень небольшое улучшение, если таковое имеется.)
Подобные замечания применимы, конечно, к другим циклам над y
.
Второе место, где вы можете ускорить процесс, - стратегия зацикливания на y
. Вы перебираете все значения y
в диапазоне, а затем проверяете, какие из них приводят к значениям k
с правильными остатками по модулю 12. Вместо этого вы можете просто зациклить правильные значения только y
, и вообще не проверяйте остатки.
Если 4*x**2
равно 4 по модулю 12, то y**2
должно быть 1 или 9 по модулю 12, и поэтому y
должно быть 1, 3, 5, 7 или 11 по модулю 12. Если 4*x**2
равно 8 по модулю 12, тогда y**2
должно быть 5 или 9 по модулю 12, поэтому y
должно быть 3 или 9 по модулю 12. И, наконец, если 4*x**2
равно 0 по модулю 12, то y**2
должно быть 1 или 5 по модулю 12 поэтому y
должно быть 1, 5, 7, 9 или 11 по модулю 12.
Я также отмечаю, что ваше сито с Эратосфеном делает бесполезную работу, проверяя делимость на все простые числа ниже i
. Вы можете остановить итерацию после проверки делимости на все простые числа, меньшие или равные квадратному корню из i
.