验证是否是素数的函数
数学界中1既是质数也不是合数
bool is_prime(int num) {if (num < 2) {return false; // 1不是素数} else if (num == 2) {return true; // 2是素数} else if (num % 2 == 0) {return false; // 偶数不是素数}for (int i = 3; i*i <= num; i+=2) { // 从3开始每+2检验num是否可以整除if (num % i == 0) {return false;}}return true;}
因为 根号n * 根号n = n,所以 n 的素因子有一个大于根号n的自然数,则必有一个小于根号n的素因子,因此只要验证小于根号n的数能否整除即可,如果小于根号n没有那么大于根号n肯定也没有。
爱拉陶斯芬筛法
int main () {int n;std::cin >> n;std::vector<bool> pr(n + 1, true);pr[1] = false;for (int i = 2; i*i < n; ++i) { // 从2开始将2的倍数全筛掉,从3开始将3的倍数全筛掉if (pr[i]) { // 因为int ij = i*i,所以只要i*i < n即可for (int ij = i*i; ij <= n; ij += i) { // 初始值为i*i,因为2*i已经被2筛过pr[ij] = false; // 优化前为 2*i}}}for (int i = 2; i <= n; ++i) { // 打印if (pr[i]) std::cout << i << std::endl;}}
- 划去2的倍数;(22,23,24,25……)
- 划去3的倍数;(32,33,34,35,3*6……)
- 划去4的倍数;
- 划去5的倍数;
- 划去6的倍数;
- 划去7的倍数;
- ……
值得我们注意的是两个乘数的选择,假设我们要筛出50以内的素数,那么第一个乘数是否需要遍历 2 至 50,如果不需要范围是多少?第二个乘数的初始值是多少?
第一个乘数:
一个合数必然是 2-√n,√n-n 两个区间内的因子的乘积,那么第一个乘数只需要在 2-√n 区间内遍历素数即可,如果一个数没有在这个区间内被筛掉那么它一定不可能在 √n-n 被筛掉,否则就大于 n 矛盾了。
第二个乘数:
初始值不需要每次都从 2 开始,因为第一个乘数已经将 2 的倍数全部筛去了,同理 3 …… 初始值设置为第一个乘数。
