说明:本处的素数判断函数,只适用于int型。在无符号int和int64上的正确性还没有进行严格的验证。
从方便性来说,用普通的素数模板即可解决一般问题。打表法只有在需要判断大量很大的整数是否为素数时,才能体现出效率优势。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
方法一:普通法基本模板
#include <cmath> bool isprime(int x) { int logo = 0, i, m; if (x==2 || x==3) logo = 1; else if ((x>4) && (x%2)) { m = sqrt(x); for (i = 3; (i<=m) && (x%i); i += 2); if (i > m) logo = 1; } return logo; }
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
方法一效率测试
#include <cmath> #include <ctime> #include <iostream> #include <cstdlib> #include <climits> using namespace std; clock_t start__; #define tic start__=clock() #define toc cout<<(clock()-start__)*1000/CLOCKS_PER_SEC<<"ms\n" bool isprime(int x) { int logo = 0, i, m; if (x==2 || x==3) logo = 1; else if ((x>4) && (x%2)) { m = sqrt(x); for (i = 3; (i<=m) && (x%i); i += 2); if (i > m) logo = 1; } return logo; } int main() { int i, t, sum; tic; printf("效率测试:判断1百万个%d至%d的“随机数”是否为素数\n", 0, RAND_MAX); srand(time(NULL)); for (sum = i = 0; i < 1000000; i++) { t = rand(); sum += isprime(t); } printf("共统计出%d个素数\n用时:", sum); toc; printf("\n"); tic; printf("效率测试:判断1百万个%d至%d的“随机数”是否为素数\n", _I32_MAX-RAND_MAX, _I32_MAX); srand(time(NULL)); for (sum = i = 0; i < 1000000; i++) { t = _I32_MAX - rand(); sum += isprime(t); } printf("共统计出%d个素数\n用时:", sum); toc; printf("\n"); return 0; }
原理:在pri[0]存储事先要打好多少个素数。init_prime在pri[1]存储2,然后p从3开始,对每个奇数遍历,如果p能整除比p小的所有素数,那么p就是素数,在pri[]末尾添加p。直到在pri[]填充完pri[0]个素数为止。
在isprime函数,如果输入的数,小于pri素数表最大的数,则在pri中二分查找x是否存在,存在则为素数,否则不是素数。如果x大于素数表最大的数,则遍历比sqrt(x)小的所有素数,当且仅当都不能被整除时,x为素数。
从isprime函数的原理看出,素数表的大小要合理。因为素数判断范围由pri[pri[0]]^2决定。要计算int,最小设置pri[0]=5000。
实际运用中,可以把pri设为全局变量。
#include <cmath> #include <algorithm> void init_prime(int pri[]) { int i, n, p; pri[1] = 2; for (p=1, n=2; n <= pri[0]; n++) { do { i = 1; p += 2; while (i<n && p%pri[i]) i++; }while (i != n); pri[n] = p; } } bool isprime(int x, int pri[]) { if (x <= pri[pri[0]]) return x == *lower_bound(pri+1, pri+pri[0]+1, x); else { int m = sqrt(x), i = 0; while (pri[++i] < m) if (x%pri[i]) return 0; return 2; } }- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include <cmath> #include <ctime> #include <iostream> #include <cstdlib> #include <climits> #include <algorithm> using namespace std; clock_t start__; #define tic start__=clock() #define toc cout<<(clock()-start__)*1000/CLOCKS_PER_SEC<<"ms\n" void init_prime(int pri[]) { int i, n, p; pri[1] = 2; for (p=1, n=2; n <= pri[0]; n++) { do { i = 1; p += 2; while (i<n && p%pri[i]) i++; }while (i != n); pri[n] = p; } } bool isprime(int x, int pri[]) { if (x <= pri[pri[0]]) return x == *lower_bound(pri+1, pri+pri[0]+1, x); else { int m = sqrt(x), i = 0; while (pri[++i] < m) if (!(x%pri[i])) return 0; return 2; } } int main() { int pri[10001] = {0}; tic; pri[0] = 5000; init_prime(pri); printf("初始化%d大小的素数表用时", pri[0]); toc; cout << "素数判断范围:" << pri[pri[0]]*1.0*pri[pri[0]] << endl << endl; tic; pri[0] = 10000; init_prime(pri); printf("初始化%d大小的素数表用时", pri[0]); toc; cout << "素数判断范围:" << pri[pri[0]]*1.0*pri[pri[0]] << endl << endl; int i, t, sum; tic; printf("效率测试:判断1百万个%d至%d的“随机数”是否为素数\n", 0, RAND_MAX); srand(time(NULL)); for (sum = i = 0; i < 1000000; i++) { t = rand(); sum += isprime(t, pri); } printf("共统计出%d个素数\n用时:", sum); toc; printf("\n"); tic; printf("效率测试:判断1百万个%d至%d的“随机数”是否为素数\n", _I32_MAX-RAND_MAX, _I32_MAX); srand(time(NULL)); for (sum = i = 0; i < 1000000; i++) { t = _I32_MAX - rand(); sum += isprime(t, pri); } printf("共统计出%d个素数\n用时:", sum); toc; printf("\n"); return 0; }