两种方法求一定范围内的所有质数
一般来说,判断一个正整数n是不是质数,通常我们的办法是:
1 将n用2~n-1来整除,如果能被整除,则不是质数;
2 对方法1优化一下,除数上限可以由n-1缩小到n^0.5;
判断某一个数差不多用上面的方法,按现在计算机的速度,就是一眨眼的功夫就计算出来了。
现在,我们需要求2~n中所有的质数,怎么办呢?
一种比较笨的方法,也就是参考求单个质数的办法写的程序,即是让i循环取2~n的值,用i整除比它小的所有质数来判断i是否是质数,如果都不可整除,则i是质数。
源代码如下:
/* 用质数相除法求所有质数的算法 bocai @ 2012.08.15 目前测试用时如下: MAXI time(s) 2^24 8 2^25 28 2^26 55 速度比筛选法慢多了。 */ #include <stdio.h> #include <limits.h> #include <vector> #include <math.h> #include <iostream> #include "time.h" using namespace std; int main(void) { // 理论:一个数是质数,则它一定不能被小于它的质数所整除 const size_t maxI = 67108864;// 2^26 测试上限 vector<int> czs; // 当前算出来的质数 czs.reserve(maxI / 20); // 当maxi较大时,质数量一般小于5% czs.push_back(2); // 2先放进去 size_t index; // 索引变量 bool isIzs; // 当前验证的数是否是质数 size_t sqrg = 2; // 平方计数 size_t sqrs = (size_t)pow(sqrg, 2); // 平方数 size_t i = 3; // 从2开始算质数 cout << "start time: " << time(NULL) <<endl; while(i < maxI) { index = 0; isIzs = true; // 标识i是否是质数 while(czs[index] < sqrg) // 还可以验证的质因数 注意index++ { if(i % czs[index] == 0) // 被整除 { isIzs = false; // 被整除,则不是质数 break; } index++; } if(isIzs && i != sqrs) { czs.push_back(i); } if(i == sqrs) // 达到了计数 { sqrg++; sqrs = (int)pow(sqrg, 2); } i++; } cout << "end time: " << time(NULL) <<endl; cout << " max i:" << maxI << " count:" << czs.size() << endl; /* for(i = 0; i < czs.size(); i++) { cout << "\t" << czs[i]; } */ return 0; }
一看这样不行啊,在虚拟机中,才2^26次方就用了55秒,太慢了。
上网一查,说是最快的方法是筛选法,于是研究一下,实现之,果然快了。筛选法的源码如下:
/* 用筛选法求所有质数的算法 bocai @ 2012.08.15 目前测试用时如下: MAXI time(s) 2^24 3 2^25 8 2^26 12 2^27 26 2^28 52 2^29 108 2^30 222 2^31 514 2^32 982 */ #include <stdio.h> #include <limits.h> #include <vector> #include <math.h> #include <iostream> #include "time.h" #include <bitset> using namespace std; int main(void) { // #define MAXI 2147483648 // 2^31 const size_t MAXI = 4294967295; // 2^32-1 bitset<MAXI> *bs = new bitset<MAXI>(); // 为1表示当前索引所表示的数为质数 bs->set(); // 预置所有位都为1 bs->reset(0); // 置0索引0 1 bs->reset(1); size_t pos = 2; size_t npos; // pos的倍数索引 cout << "start time: " << time(NULL) <<endl; while(pos < MAXI) { if(bs->test(pos)) // pos是质数,把后面它的倍数的全置0 { npos = pos + pos; // 从2倍起 while(npos > pos // 预防溢出情况 && npos < MAXI) { bs->reset(npos); npos += pos; // 循环 } } pos++; } cout << "end time: " << time(NULL) <<endl; cout << " max i:" << (MAXI - 1) << " count:" << bs->count() << endl; /* for(int i = 2; i < bs.size(); i++) { if(bs.test(i)) { cout << "\t" << i; } } */ return 0; }
在源代码级别不知还有没优化的地方,请多指教。