素数筛法和测试

来源:互联网 发布:vc socket编程 并发 编辑:程序博客网 时间:2024/05/19 11:45

一。筛法

线性时间筛法:

一边制作质数表,一边删掉每个数的质数倍,时间复杂度就能达到O(N) 。

const  int  N  =  20000000 ;bool  sieve [ N ]; void  eratosthenes (){    vector < int >  prime ;    for  ( int  i = 2 ;  i < N ;  i ++)    {        if  (! sieve [ i ])  prime . push_back ( i );        for  ( int  j = 0 ;  i * prime [ j ]< N ;  j ++)        {            sieve [ i * prime [ j ]] =  true ;            if  ( i  %  prime [ j ] ==  0 )  break ;        }    }}

6n±1 Method

原理是:只拿2 和3 这两个质数先筛过一遍,剩下的数字则用试除法验证是不是质数。

2 和3 的最小公倍数是6 ,我们就把所有数字分为6n 、 6n+1 、 6n+2 、 6n+2 、 6n+3 、 6n+4 、 6n+5 六种( n 是倍率)。除以六会余零的数字为6n ,除以六会余一的数字为6n+1 ,以此类推。

可以看出6n 、 6n+2 、 6n+3 、 6n+4 会是2 或3 的倍数,不属于质数。因此,只要验证6n+1 和6n+5 是不是质数就可以了。( 6n+5 也可以写成6n-1 ,意义不变。)

6n-1 到6n+1 ,再到下一个6n-1 ,再到6n+1 ,把这些要验证的数字由小排到大,可以发现之间的差值会是2 4 2 4 2 4 . .. 不断跳二跳四。实作程式码时,就可以直接用加法加二加四,而不必用乘法及加减法计算6n-1 、 6n+1 ,如此一来程式的执行效率会好一点。

验证的顺序是:数字2 和3 明显的是质数,不必验证;若是从数字5 开始验证,那么下一个要验证的数字就是5+2 ,再下一个就是5+2+4 ,再下一个就是5+2+4+2 ,如此不断下去。

// 以试除法判断质数bool  isprime ( int  n ){    for  ( int  i = 5 ;  i * i <= n ;  i += 2 )        if  ( n % i  ==  0 )            return  false ;    return  true ;} // 只检查6n±1。这些数字的间隔为2 4 2 4....void  make_prime (){    cout  <<  "找到质数2" ;    cout  <<  "找到质数3" ;    for  ( int  i = 5 ,  gap = 2 ;  i < 1000000 ;  i += gap ,  gap = 6 - gap )        if  ( isprime ( i ))            cout  <<  "找到质数"  <<  i ;}
二。质数测试,测试一个数字是否为质数。
整除性测试法。
依照质数定义,一个质数p 不会被大于1 且小于p 的数字整除,只要把这些数字都拿来试除,就可以判定一个数字是不是质数。

bool  divisibiity_test ( int  n ){    // 穷举n所有可能的因数一一试除。    for  ( int  d = 2 ;  d < n ; ++ d )        if  ( n  %  d  ==  0 )            return  false ;    //不是质数    return  true ;     //是质数}

bool  divisibiity_test ( int  n ){    // 一个数字n不会有大于sqrt(n)的质因数(除了n本身以外)    int  sqrt_n  =  sqrt ( n );    for  ( int  d = 2 ;  d <= sqrt_n ; ++ d )        if  ( n  %  d  ==  0 )            return  false ;    return  true ;}

费玛小定理:

若n是质数,a小于n,则a^n ≡ a (mod n)。
若n是质数,a小于n,a不是零,则a^(n-1) ≡ 1 (mod n)。
费玛质数测试法是运用费玛小定理而想出的方法:

n是质数,费玛小定理一定成立:a^(n-1) % n = 1一定成立。
n是合数,费玛小定理可能成立:a^(n-1) % n = 1可能成立。

当a^(n-1) % n = 1成立,就推定n是质数。
此算法的结果不一定正确。通过测试的数字,可能是合数或质数;无法通过测试的数字,一定是合数。

bool  fermat_primality_test ( int  n ){    // 随便取得一个数值当作a,    // 但是必须大于1、小于n,才有意​​义。// srand(time(0));    int  a  =  rand () % ( n - 2 ) +  2 ;     // 计算a^(n-1) % n的值,存于x中。    int  x  =  1 ;    for  ( int  i = 1 ;  i < n ; ++ i )         x  =  x  *  a  %  n ;    return  x  ==  1 ;// return pow(a, n-1, n) == 1;}

Miller-Rabin Algorithm
此算法的结果不一定正确。通过测试的数字,可能是合数或质数;无法通过测试的数字,一定是合数。

bool  miller_rabin ( int  n ){    if  ( n  <  2 )  return  false ; // srand(time(0));    int  a  =  rand () % ( n - 2 ) +  2 ;     int  u  =  n - 1 ,  t  =  0 ;    while  ( u  %  2  ==  0 )  u  >>=  1 ,  t ++;     int  x  =  pow ( a ,  u ,  n );    // x = a ^ u % n;    if  ( x  ==  1  ||  x  ==  n - 1 )  return  true ;     for  ( int  i = 0 ;  i < t - 1 ;  i ++)    {        x  =  mul ( x ,  x ,  n );    // x = x * x % n;        if  ( x  ==  1 )  return  false ;        if  ( x  ==  n - 1 )  return  true ;    }    return  false ;}




原创粉丝点击