zoukankan      html  css  js  c++  java
  • [hiho第92周]Miller-Rabin素性测试的c++实现

    证明:

    如果n是素数,整数$a$ 与$n$ 互素,即$n$ 不整除$a$ ,则${a^{n - 1}} equiv 1(mod n)$ ,如果能找到一个与$n$ 互素的整数$a$ ,是的上式不成立,则可以断定$n$ 是合数,反之则不成立,这类合数我们称之为Carmichael数。当上式成立时,称$n$ 为以$a$ 为底的伪素数。

    以上测试素数的方法称为fermat测试。

    Miller-Rabin素性检验是在上面的基础上加上一个二次探测定理。

    强伪素数:设$n - 1 = {2^s}t$ ,$2 mid t$ ,$b$ 与$n$ 互素。若${b^t} equiv 1(mod n)$ 或存在$r$ , $0 le r le s$ 使得${b^{{2^r}t}} equiv - 1(mod n)$ ,则称n为以b为底的强伪素数。

    当$n$ 为素数时,他一定是从任何数$b$ 为基的强伪素数,以$b$为基的强伪素数一定是以$b$为基的伪素数。

    二次探测定理:如果p是奇素数,则 ${x^2} equiv 1(mod p)$ 的解为$x equiv 1$ 或 $x equiv p - 1(mod p)$

    如果${a^{n - 1}} equiv 1(mod n)$成立,Miller-Rabin算法不是立即找另一个$a$进行测试,而是看$n-1$ 是不是偶数。如果$n-1$ 是偶数,另$u = frac{{n - 1}}{2}$,并检查是否满足二次探测定理即${a^u} equiv 1$或${a^u} equiv n - 1(mod n)$。若不满足,则为合数。

    定理:若n是奇合数,则在区间$0 < b < n$ 中,最多有25%的数$b$ ,能使$n$ 是以$b$ 为基的强伪素数。

    所以,结果的正确率为$1 - frac{1}{{{4^k}}}$

    复杂度:$O(Slog n)$

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cstdlib>
     5 #include<iostream>
     6 #include<cmath>
     7 typedef long long ll;
     8 using namespace std;
     9 const int S=20;
    10 ll mod_mul(ll a,ll b,ll p){
    11     ll res=0;
    12     a%=p,b%=p;
    13     while(b){
    14         if(b&1)res=(res+a)%p;
    15         a=(a<<1)%p;
    16         b>>=1;
    17     }
    18     return res;
    19 }
    20 ll mod_pow(ll x,ll n,ll p){
    21     ll res=1;
    22     while(n){
    23         if(n&1)res=mod_mul(res,x,p);
    24         x=mod_mul(x,x,p);
    25         n>>=1;
    26     }
    27     return res;
    28 }
    29 
    30 bool check(ll a,ll n,ll x,ll t){//判断是否为合数 
    31     ll ret=mod_pow(a,x,n);
    32     ll last=ret;
    33     for(int i=1;i<=t;i++){
    34         ret=mod_mul(ret,ret,n);
    35         if(ret==1&&last!=1&&last!=n-1)return 1;
    36         last=ret;
    37     }
    38     if(ret!=1) return 1;//fermat测试 
    39     return 0;
    40 }
    41 
    42 bool Miller_Rabin(ll n){
    43     if(n<2)return 0;
    44     if(n==2)return 1;
    45     if((n&1)==0)return 0;
    46     ll x=n-1,t=0;
    47     while((x&1)==0)x>>=1,t++;
    48     for(int i=0;i<S;i++){
    49         ll a=rand()%(n-1)+1;
    50         if(check(a,n,x,t))return 0;//合数
    51     }
    52     return 1;
    53 }
    54 
    55 int main(){
    56     ll t,n;
    57     scanf("%lld",&t);
    58     while(t--){
    59         scanf("%lld",&n);
    60         if(Miller_Rabin(n))printf("Yes
    ");
    61         else printf("No
    ");
    62     }
    63     return 0;
    64 }
  • 相关阅读:
    C/S WinFORM 快速开发框架 MyRapid快速开发框架更新日志 ---数据权限控制
    C/S WinFORM 快速开发框架 MyRapid快速开发框架更新日志 ---自动生成操作手册
    C/S WinFORM 快速开发框架 MyRapid快速开发框架更新日志 ---添加模块流程图
    代码分享:给窗体添加水印
    版本需更新提醒
    如何做好软件自动更新
    做项目管理踩过的坑
    团队开发的代码管理(VS)
    Java8尽管很香,你想过升级到Java11吗?会踩那些坑?
    这个 Spring 循环依赖的坑,90% 以上的人都不知道
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7692812.html
Copyright © 2011-2022 走看看