Проверка числа на простоту
Как можно проверить число на простоту? Очевидно – если у числа нет делителей больше единицы и меньше самого числа, то оно простое. Значит, надо перебрать числа до $N$, и если оно поделится хотя бы на одно из них, то число окажется составным.
bool if_prime(int N) {
/* Перебираем с двух, т. к. на 0 нельзя делить, а на 1 поделится любое число,
до N - 1, т. к. любое число делится само на себя.*/
for (int i = 2; i < N; ++i) {
if (N % i == 0)
return false;
}
return true;
}
Конечно, этот алгоритм сработает и будет возвращать правильные ответы. Но насколько быстро? Очевидно, что за $O(N)$ операций, но если $N$ окажется большим числом, например $10 ^ 9 + 7$? Как оптимизировать этот алгоритм?
Оптимизация в данном случае проста. Понятно, что если мы рассматриваем число $24$, нам не нужно проверять делимость на $23$, $22$, $21$, $20$ и так далее. Наибольший делитель числа $24$ – $12$, то есть $1 \over 2$. Надо ли все проверять до $\frac{1}{2}N$? Можно еще быстрее.
Выпишем все возможные разложения $24$ на два множителя, начиная с $2$:
$2 \times 12$
$3 \times 8$
$4 \times 6$
$6 \times 4$
$8 \times 3$
$12 \times 2$
Мы видим, что после какого-то момента произведения начинают повторяться. И даже отчасти понятно, когда. Для большего понимания рассмотрим еще один пример – $36$:
$2 \times 18$
$3 \times 12$
$4 \times 9$
$6 \times 6$
$9 \times 4$
$12 \times 3$
$18 \times 2$
Теперь стало ясно, что произведения повторяются после $\sqrt {N}$. Это и есть та самая граница, до которой нужно перебирать делители:
bool if_prime(int N) {
/*Корень из числа – это число в степени 1/2.
Также лучше увеличить границы поиска на 1 элемент, т.к. int()
округляет вниз.*/
for (int i = 2; i <= int(sgrt(N)) + 1; ++i) {
if (N % i == 0)
return false;
}
return true;
}