上一次写到了厄拉多塞筛法,说到厄拉多塞筛法随着计算上限的成倍增加,计算时间也会成倍增加。
这次的欧拉筛法在时间这方面会比厄拉多塞筛法好很多。
先上代码:
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <stdint.h>
#define MAX 1000000
int main()
{
uint64_t* prime;
prime = (uint64_t*)malloc(MAX*sizeof(uint64_t));
memset(prime, 0, MAX);
bool isprime[MAX];
memset(isprime, true, sizeof(isprime));
uint64_t index = 0;
for (uint64_t i = 2; i < MAX; ++i)
{
if (isprime[i])
{
prime[index] = i;
++index;
}
for (uint64_t j = 0; j < index && i * prime[j] < MAX; ++j)
{
isprime[i*prime[j]] = false;
if (i % prime[j] == 0)
{
break;
}
}
}
uint64_t sum = 0;
for (uint64_t i = 0; i < index; ++i){
sum += prime[i];
}
printf("%llu\n", sum);
free(prime);
return 0;
}
欧拉筛法的思路和厄拉多塞筛法很像,素数的倍数标记成合数,但是标记的方法有区别。
欧拉筛法把数字i和已知的所有素数相乘,然后把结果标记为合数。
重要的是计算i%prime[j]是否为0,如果为0则break掉现在的循环。
这一步的意思是,每一个合数只被它最小的素数因数排除一次。
比如说12,12的第一次可能被排除的情况是i=4,此时经过for循环以后,因为4*prime[0]=8,所以首先把8给排除掉,然后因为4可以整除prime[0]也就是2,所以break掉for循环,也就是没有排除掉12.
实际上12会在6的时候被排除,此时6在排除过12以后,break掉for循环,不会排除18,因为18是需要9来排除的。
这样在厄拉多塞筛法中重复被排除的12,18之类的数字就不会被重复排除,算法的效率也就得到了提高。
但是我在想要把MAX设置为十亿,跟厄拉多塞筛法做一个比拼时,发现了一个问题,就是欧拉筛法需要一个数组来保存目前已知的所有素数。
但是即使我已经用了malloc,但是还是不能分配到这么大的内存,直接StackOverflow了。
所以先把算法的实现方法写在这里,等我Google到方法后再修改。