日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

转载 素性测试

發布時間:2025/3/15 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转载 素性测试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  原文地址https://www.douban.com/note/271270932/

  對一個數是n否為素數的判斷可以從2到根號n依次去除n,如果n能被其中一個整除則說明n不是素數,否則n是素數。還可以用厄拉多塞篩法,采用構造素數表的方式,從2起,依次列出后續數字,如果某個數是前面數字的倍數,則從表中刪除,即刪掉所有素數的倍數,最后得到的表就是一個全是素數的表。用于程序實現的話,可以設置一個棧,初始時棧內只有一個元素2,令從3起依次累加,并判斷如果i不是棧內任何一個數的倍數,則令i進棧,否則繼續循環,直到達到要求為止。
???????以上兩種方式對于較小的數的判斷還可以使用,但是當數字達到很大的時候,這兩種方式的效率都會很低,因而我們要尋求更快的判斷一個數是否為素數的方式。首先看幾個定理:

定理:設n>1是一個奇數,如果對于n-1的每一個素因子q存在一個整數a使得下式成立,則n為素數:
a^(n-1)≡1 (mod n)
a^((n-1)/q)≠1 (mod n)
費馬小定理:若p是素數,則對于任意的正整數a≠0(mod p),有
a^(p-1)≡1(mod p)
素數重要性質: a^((p-1)/2)≡ (a/p)(mod p),其中p是素數,(a/p) 是雅可比符號

根據以上定理我們可以得到一些素性判定的效率較高的方法。下面介紹三種:
Fermat素性測試,Lehmann素性測試和Solovay-Strassen 素性測試。

第一種,Fermat素性測試:
算法Fermat(n,t),其中n>2為奇數, t為測試次數.
1) 對 i 從1 到 t 做如下循環:
??1.1) 隨機選擇 a,1<a<n-1;
??1.2) 計算d=gcd(a,n),如果d>1,則返回“合數”。否則
??1.3) 計算 r ≡ a ^(n-1) (mod n);
??1.4) 若r≠1 ,則返回“合數”。
2) 返回“素數”。
算法主要應用了費馬小定理,但a^(p-1)≡1(mod p)僅是素數的必要條件。上述算法將一個合數判斷為素數的出錯概率為1/2^t,但是返回合數的判定總是對的。只要增加測試次數t,就可以把出錯概率降至趨近于0。

第二種,Lehmann素性測試:
1) 對i從1到t 做如下循環:
1.1)選擇一個小于n的隨機數b;
1.2) 計算b^((n-1)/2) mod n;
1.3) 如果b^((n-1)/2)≠1或-1,那么返回合數;(n肯定不是素數)
2) 返回素數。(n不是素數的可能性至多是50%)
算法主要運用了上面提到的第一條定理,2是素數且是n-1的素因子,在這里代替了q。

第三種,Solovay-Strassen 素性測試
1) 對i從1到t 做如下循環:
??1.1) 選擇一個小于n的隨機數b;
??1.2) 計算j≡b^((n-1)/2) mod n;
??1.3) 如果j≠1或-1,則返回n不是素數;
??1.4) 計算Jacobi符號J(b,n)=(b/n);
??1.5) 如果 j≠(b/n),返回n不是素數。
2) 返回n是素數
算法中的1.3同樣使用了第一條定理判斷出合數。而后又用素數性質加強了判斷,所以這一測試準確度更高。

???????三種算法都存在關鍵性一步就是計算某個數的冪次模n值,如Fermat素性測試中,計算計算 r ≡ a ^(n-1) (mod n),如果采用對a逐次去計算的方式,時間復雜度是O(n),還不如開始說的兩種算法。所以要想得到高效的素性判定算法,就要對這一步進行優化。
???????逐次計算的一個缺點是,沒有充分利用每次循環中已得到的信息。進而可以想到,如果能像人工計算時一樣,記錄下a^2 mod n, a^4 mod n,……,每次計算時根據需求選用這些已得到的值,比如計算a^254 mod 255。算出a^2 mod 255, a^4 mod 255,……,a^128 mod 255,就可以根據已算得的結果計算a^254 mod 255=a^128*a^64*a^32*a^16*a^8*a^4*a^2 mod 255,充分利用了已有信息。
??????于是一個自然的想法就是,首先循環一遍把a^i mod n的值記錄在一個表中,其中i是2的冪次,然后求出n-1的二進制表示由低位到高位存儲在數組中,r初始時為1,遍歷數組,某位為1時則把表中對應位置的a^i mod n乘以r的值賦值給r,這樣循環一遍后即得到了a^(n-1)mod n的值,速度大大提高。原來計算a^64需要64次,改進后只需計算a^2,a^4, a^8,a^16,a^32,a^64 mod n共6次即可,并且經過這6次計算,a的1~64次方模n都可被計算出來,多次測試中均可使用,即使對很大的測試次數也有很高效率。對于long long 型數據,最大只需循環64次即可。時間復雜度由O(n)降到了O(logn)。
????????這一步實現了,其他細節只需要稍加調試即可,這里僅給出Solovay-Strassen 素性測試的代碼。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define MAX_TIME 11111
#define DATA_TYPE long long
bool Solovay_Strassen (DATA_TYPE n,int t);
int Jacobi(DATA_TYPE a,DATA_TYPE n);
DATA_TYPE ComputeR(DATA_TYPE a,DATA_TYPE k,DATA_TYPE n);//計算r=a^k mod n
int DecToBin(DATA_TYPE num,int a[]); //十進制轉化成二進制,返回二進制位數
int main()
{
????????DATA_TYPE n;
????????while(1)
????????{
????????????????printf("請輸入要判斷的數:\n");
????????????????scanf("%lld",&n);
????????????????if(n<=1||(n>2&&n%2==0)||!Solovay_Strassen(n,n>MAX_TIME?MAX_TIME:n-2))
????????????????????????printf("%lld不是素數\n",n);
????????????????else
????????????????????????printf("%lld是素數\n",n);
????????????????printf("\n");
????????}
????????return 0;
}
bool Solovay_Strassen (DATA_TYPE n,int t)
{
????????int i;
????????DATA_TYPE Rand_Num,r,jac;
????????srand((unsigned int)time(NULL));
????????for(i=0;i<t;i++)
????????{
????????????????//注釋起來這一段用來判斷是否有隨機數重復,如重復則重新生成,在n足夠大時,這一段理論上可以忽略
/* DATA_TYPE Choosed[MAX_TIME]; //記錄已選的隨機數
????????????????bool flag; //標記是否有重復
????????????????do
????????????????{
????????????????????????flag=0;
????????????????????????do
????????????????????????{
????????????????????????????????Rand_Num=rand()%n;
????????????????????????}while(Rand_Num<=1||Rand_Num>n-1);
????????????????????????for(int j=0;j<i;j++)
????????????????????????{
????????????????????????????????if(Rand_Num==Choosed[j]) //已選擇過
????????????????????????????????{
????????????????????????????????????????flag=1; //置標記位為1
????????????????????????????????????????break;
????????????????????????????????}
????????????????????????}
????????????????}while(flag);
????????????????Choosed[i]=Rand_Num;*/
????????????????do
????????????????{
????????????????????????Rand_Num=rand()%n;
????????????????}while(Rand_Num<=1||Rand_Num>n-1);
????????????????r=ComputeR(Rand_Num,(n-1)/2,n);
????????????????if(!(1==r ||r==n-1))
????????????????????????return 0;
????????????????jac=Jacobi(Rand_Num,n);
????????????????if(jac<0)
????????????????????????jac=n+jac;
????????????????if(r!=jac)
????????????????????????return 0;
????????}
????????return 1;
}

int Jacobi(DATA_TYPE a,DATA_TYPE n)
{
????????DATA_TYPE temp,e=0,a1,n1;
????????int s;
????????if(0==a ||1== a)
????????????????return 1;
????????temp=a;
????????while(temp%2==0)
????????{
????????????????temp/=2;
????????????????e++;
????????}
????????a1=temp;
????????if(0== e%2)
????????????????s=1;
????????else
????????{
????????????????if(1== n%8||7== n%8)
????????????????????????s=1;
????????????????else if(3== n%8|| 5== n%8)
????????????????????????s=-1;
????????}
????????if(3== n%4&&3== a1%4)
????????????????s=-s;
????????n1=n%a1;
????????if(1== a1)
????????????????return s;
????????else
????????????????return s*Jacobi(n1,a1);
}

int DecToBin(DATA_TYPE num,int a[]) //十進制轉化成二進制,返回二進制位數
{
????????int BitNum;
????????for(BitNum=0;num;BitNum++)
????????{
????????????????if(0==num%2)
????????????????????????a[BitNum]=0;
????????????????else
????????????????????????a[BitNum]=1;
????????????????num/=2;
????????}
????????return BitNum;
}

DATA_TYPE ComputeR(DATA_TYPE a,DATA_TYPE k,DATA_TYPE n)
{
????????DATA_TYPE tmp;
????????DATA_TYPE Power[8*sizeof(DATA_TYPE)]={0};
????????int i,BitNum;
????????int Bin[8*sizeof(DATA_TYPE)]={0};
????????BitNum=DecToBin(k,Bin); //將n-1轉換成二進制,二進制位數賦給BitNum
????????tmp=a;
????????Power[0]=tmp;
????????for(i=1;i<BitNum;i++)
????????{
????????????????tmp=(tmp*tmp)%n;
????????????????Power[i]=tmp;
????????}
????????for(i=0,tmp=0;i<BitNum;i++)
????????{
????????????????if(Bin[i]==1)
????????????????{
????????????????????????if(0==tmp) tmp=1;
????????????????????????tmp=(tmp*Power[i])%n;
????????????????}
????????}
????????return tmp;
}

轉載于:https://www.cnblogs.com/leo0000/p/5720244.html

總結

以上是生活随笔為你收集整理的转载 素性测试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。