原文:http://blog.csdn.net/u011002533/article/details/62057426
1.gcd算法
- int gcd(int a, int b)
- {
- return (a==0)?b:gcd(b%a, a);
- }
- //递推法
- int gcd(int m, int n)
- {
- while(m>0)
- {
- int c = n % m;
- n = m;
- m = c;
- }
- return n;
- }
- /* 连续整数试探算法,计算最大公约数 */
- int gcd(int m, int n)
- {
- if(m>n) {
- int temp = m;
- m = n;
- n = temp;
- }
- int t = m;
- while(m%t || n%t)
- {
- t--;
- }
- return t;
- }
2.素数判断(该内容转载自http://blog.csdn.net/arvonzhang/article/details/8564836)
- //最笨做法
- bool IsPrime(unsigned n)
- {
- if (n<2)
- {
- //小于2的数即不是合数也不是素数
- throw 0;
- }
- for (unsigned i=2;i<n;++i)
- {
- //和比它小的所有的数相除,如果都除不尽,证明素数
- if (n%i==0)
- {
- //除尽了,则是合数
- return false;
- }
- }
- return true;
- }
- //一般做法
- num = 0;
- for(i=2; i<=n; i++)
- { for(j=2; j<=sqrt(i); j++)
- if( j%i==0 ) break;
- if( j>sqrt(i) ) prime[num++] = i;
- }
- //素数表做法
- bool IsPrime2(unsigned n)
- {
- if ( n < 2 )
- { // 小于2的数即不是合数也不是素数
- throw 0;
- }
- static unsigned aPrimeList[] = { // 素数表
- 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
- 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 113,
- 193, 241, 257, 337, 353, 401, 433, 449, 577, 593, 641,
- 673, 769, 881, 929, 977, 1009, 1153, 1201, 1217, 1249,
- 1297,1361, 1409, 1489, 1553, 1601, 1697, 1777, 1873,
- 1889, 2017, 2081, 2113, 2129, 2161, 2273, 2417, 2593,
- 2609, 2657, 2689, 2753, 2801, 2833, 2897, 3041, 3089,
- 3121, 3137, 3169, 3217, 3313, 3329, 3361, 3457, 3617,
- 3697, 3761, 3793, 3889, 4001, 4049, 4129, 4177, 4241,
- 4273, 4289, 4337, 4481, 4513, 4561, 4657, 4673, 4721,
- 4801, 4817, 4993, 5009, 5153, 5233, 5281, 5297, 5393,
- 5441, 5521, 5569, 5857, 5953, 6113, 6257, 6337, 6353,
- 6449, 6481, 6529, 6577, 6673, 6689, 6737, 6833, 6961,
- 6977, 7057, 7121, 7297, 7393, 7457, 7489, 7537, 7649,
- 7681, 7793, 7841, 7873, 7937, 8017, 8081, 8161, 8209,
- 8273, 8353, 8369, 8513, 8609, 8641, 8689, 8737, 8753,
- 8849, 8929, 9041, 9137, 9281, 9377, 9473, 9521, 9601,
- 9649, 9697, 9857
- };
- const int nListNum = sizeof(aPrimeList)/sizeof(unsigned);//计算素数表里元素的个数
- for (unsigned i=2;i<nListNum;++i )
- {
- if(n/2+1<aPrimeList[i])
- {
- return true;
- }
- if(0==n%aPrimeList[i])
- {
- return false;
- }
- }
- /*由于素数表中元素个数是有限的,那么对于用素数表判断不到的数,就只有用笨蛋办法了*/
- for (unsigned i=aPrimeList[nListNum-1];i<n/2+1;i++ )
- {
- if (0==n%i)
- {
- // 除尽了,合数
- return false;
- }
- }
- return true;
- }
- 费马小定理:对于两个互质的素数N和P,必有:N^(P-1)%P=1
- 算法思路:
- 对于N,从素数表中取出任意的素数对其进行费马测试,如果取了很多个素数,N仍未测试失败,那么则认为N是素数。当然,测试次数越多越准确,但一般来讲50次就足够了。
- bool IsPrime3(unsigned n)
- {
- if ( n < 2 )
- {
- // 小于2的数即不是合数也不是素数
- throw 0;
- }
- static unsigned aPrimeList[] = {
- 2, 3, 5, 7, 11, 17, 19, 23, 29, 31, 41,
- 43, 47, 53, 59, 67, 71, 73, 79, 83, 89, 97
- };
- const int nListNum = sizeof(aPrimeList) / sizeof(unsigned);
- for (int i=0;i<nListNum;++i)
- {
- // 按照素数表中的数对当前素数进行判断
- if (1!=Montgomery(aPrimeList[i],n-1,n)) // 蒙格马利算法
- {
- return false;
- }
- }
- return true;
- }
- 拉宾米勒测试算法---目前最快的判断素数算法
- 拉宾米勒测试是一个不确定的算法,只能从概率意义上判定一个数可能是素数,但并不能确保。算法流程如下:
- 1.选择T个随机数A,并且有A<N成立。
- 2.找到R和M,使得N=2*R*M+1成立。
- 快速得到R和M的方式:N用二进制数B来表示,令C=B-1。因为N为奇数(素数都是奇数),所以C的最低位为0,从C的最低位的0开始向高位统计,一直到遇到第一个1。这时0的个数即为R,M为B右移R位的值。
- 3.如果A^M%N=1,则通过A对于N的测试,然后进行下一个A的测试
- 4.如果A^M%N!=1,那么令i由0迭代至R,进行下面的测试
- 5.如果A^((2^i)*M)%N=N-1则通过A对于N的测试,否则进行下一个i的测试
- 6.如果i=r,且尚未通过测试,则此A对于N的测试失败,说明N为合数。
- 7.进行下一个A对N的测试,直到测试完指定个数的A
- 通过验证得知,当T为素数,并且A是平均分布的随机数,那么测试有效率为1 / ( 4 ^ T )。如果T > 8那么测试失误的机率就会小于10^(-5),这对于一般的应用是足够了。如果需要求的素数极大,或着要求更高的保障度,可以适当调高T的值。
- bool RabbinMillerTest( unsigned n )
- {
- if (n<2)
- {
- // 小于2的数即不是合数也不是素数
- throw 0;
- }
- const unsigned nPrimeListSize=sizeof(g_aPrimeList)/sizeof(unsigned);//求素数表元素个数
- for(int i=0;i<nPrimeListSize;++i)
- {
- // 按照素数表中的数对当前素数进行判断
- if (n/2+1<=g_aPrimeList[i])
- {
- // 如果已经小于当前素数表的数,则一定是素数
- return true;
- }
- if (0==n%g_aPrimeList[i])
- {
- // 余数为0则说明一定不是素数
- return false;
- }
- }
- // 找到r和m,使得n = 2^r * m + 1;
- int r = 0, m = n - 1; // ( n - 1 ) 一定是合数
- while ( 0 == ( m & 1 ) )
- {
- m >>= 1; // 右移一位
- r++; // 统计右移的次数
- }
- const unsigned nTestCnt = 8; // 表示进行测试的次数
- for ( unsigned i = 0; i < nTestCnt; ++i )
- {
- // 利用随机数进行测试,
- int a = g_aPrimeList[ rand() % nPrimeListSize ];
- if ( 1 != Montgomery( a, m, n ) )
- {
- int j = 0;
- int e = 1;
- for ( ; j < r; ++j )
- {
- if ( n - 1 == Montgomery( a, m * e, n ) )
- {
- break;
- }
- e <<= 1;
- }
- if (j == r)
- {
- return false;
- }
- }
- }
- return true;
- }
原理就是标记,防止重复判断。比如2是素数,所有是2的倍数都不是素数,然后标记上,接着判断3,执行到根下,这样就会得到一个素数表,所有没有被标记的都是素数
- 素数筛法
- 以下转载自http://blog.csdn.net/tongyongzh/article/details/6693409
- #include <cstdlib>
- #include <cmath>
- using namespace std;
- const int MAX=1000;
- int main()
- {
- int i=0,j=0,n=sqrt(MAX)+1;
- int a[MAX+1]={0};
- for(i=2;i<=n;i++) //筛选循环
- for(j=2;j<=MAX/i;j++)
- a[j*i]=1;
- for(i=2;i<=MAX;i++)
- if(a[i]==0)
- {
- cout.width(7);
- cout<<i<<" ";
- }
- system("pause");
- return 0;
- }
线性筛法
- <span style="font-size:24px;">int a[MAX_N+1];
- int p[MAX_N+1];
- int nCount=0;
- void Init(int n) //线性筛法,不过在小范围上(约n<1e7)不比上一个方法快
- {
- for (int i=2;i<=n;i++)
- {
- if (a[i]==0)
- {
- p[++nCount]=i;
- }
- for (int j=1,k; (j<=nCount) && (k=i*p[j])<=n; j++) //筛选循环
- {
- a[k] = 1 ;
- if (i%p[j] == 0) break;
- }
- }
- }
- #include <iostream>
- int main(void)
- {
- Init(MAX_N);
- for(int n=1; p[n]>1; ++n)
- {
- printf("%5d", p[n]);
- }
- return 0;
- }</span>