[算法]Miller Robbin素数判定

Miller Robbin素数判定

一、实现原理

我们以前都是怎么判断素数的呢:

inline int is_prime(int n){
    if(n==1) return 0;
    for(int i=2;i<=sqrt(n);i++){
        if(n%i==0) return 0;
    }
    return 1;
} 

现在,我们希望更快的判断一个数是否为素数。
我们可以借助费马小定理来判断:
如果p是一个质数,而整数a不是p的倍数,则有
\[a^{p-1}\equiv 1\pmod p\]
Miller Robbin素数判定就是根据上述定理实现的,如果我们随机枚举一个\(a\),如果满足这个同余式,那么\(p\)是素数。
需要注意的是,我们这样判断素数的方法利用的是费马小定理的逆定理。不幸的是,费马小定理的逆定理并不是一个真命题。

  • 存在\(a=2,p=341\)时满足费马小定理,而\(341=11*31\)却是合数

我们把像341这样的数称作伪素数。实际上,伪素数有无穷多组。
这意味着一次判断不足以保证我们的程序正确。当然,解决这个问题也十分简单。
我们只需要重复操作大约30次,便能将正确率提升到我们期待的水平。
另外,我们使用快速幂来计算\(a^{p-1}\)。

二、模板

模板题:AT807 素数、コンテスト、素数

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int qpow(int a,int b,int mod){//快速幂
    int res=1;
    while(b){
        if(b&1) res=(res%mod*a)%mod;
        b>>=1;
        a=(a%mod)*a%mod;
    }
    return res;
}
inline int miller_robbin(int num){//核心代码
    for(int i=1;i<=30;i++){
        int base=rand()%(num-1)+1;
        if(qpow(base,num-1,num)!=1) return 0;
    }
    return 1;
}
signed main(){
    int num;
    scanf("%d",&num);
    if(num==1){
        printf("NO");
        return 0;
    }
    miller_robbin(num)?printf("YES\n"):printf("NO\n");
    return 0;
}

附赠一道水题:(主要是练习素数判定)
AT1476 素数判定

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll qpow(ll a,ll b,ll mod){
    ll res=1;
    while(b){
        if(b&1)res=(res%mod*a)%mod;
        a=(a%mod)*a%mod;
        b>>=1;
    }
    return res;
}
bool query_prime(ll x)
{
    if(x==2)return true;
    if(x==1)return false;
    for(int i=1;i<=30;i++){
        ll base=rand()%(x-1)+1;
        if(qpow(base,x-1,x)!=1)return false;
    }
    return true;
}
int main()
{
    srand(time(NULL));
    ll num;
    scanf("%lld",&num);
    if(query_prime(num)||(num%2!=0&&num%3!=0&&num%5!=0&&num!=1))printf("Prime\n");
    else printf("Not Prime\n");
    return 0;
}

三、小结

使用Miller Robbin素数判定,我们可以将复杂度降低至\(O(logn)\)级别(常数级可以被忽略)。这样比原来的方法会快很多。

原文地址:https://www.cnblogs.com/cyanigence-oi/p/11708604.html

时间: 2024-11-05 18:32:13

[算法]Miller Robbin素数判定的相关文章

Miller-Rabin算法 codevs 1702 素数判定 2

转载自:http://www.dxmtb.com/blog/miller-rabbin/ 普通的素数测试我们有O(√ n)的试除算法.事实上,我们有O(slog³n)的算法. 定理一:假如p是质数,且(a,p)=1,那么a^(p-1)≡1(mod p).即假如p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒等于1.(费马小定理) 该定理的逆命题是不一定成立的,但是令人可喜的是大多数情况是成立的. 于是我们就得到了一个定理的直接应用,对于待验证的数p,我们不断取a∈[1,p-1]且a∈

数学#素数判定Miller_Rabin+大数因数分解Pollard_rho算法 POJ 1811&amp;2429

素数判定Miller_Rabin算法详解: http://blog.csdn.net/maxichu/article/details/45458569 大数因数分解Pollard_rho算法详解: http://blog.csdn.net/maxichu/article/details/45459533 然后是参考了kuangbin的模板: http://www.cnblogs.com/kuangbin/archive/2012/08/19/2646396.html 模板如下: //快速乘 (a

10^9以上素数判定,Miller_Rabin算法

#include<iostream> #include<cstdio> #include<ctime> #include<string.h> #include<stdlib.h> #define LL long long using namespace std; const int S=20;//随机算法判定次数,S越大,判错概率越小 LL ans; //给定一个数,判断是否是素数(常用long long大数) LL mult_mod(LL a,

素数判定Miller_Rabin 算法详解

最简单直观简单的素数判定方法就是试除法.对于判断数n是否是素数,我们从2开始一直到sqrt(n).如果找到一个因子则判断n不是素数,否则是素数.代码如下: bool isPrime( long long n ) { for(long long i = 2; i*i <= n; i++) { if(n%i == 0) return false; } return true; } 如果要找到成1~n的所有素数那么这个时间代价就变为O(n^2),很多时候是不可接受的.所以随着学习的深入,我们了解到了素

[Miller-Rabin][CODEVS1702]素数判定2 解题报告

题面描述:判定一个数P∈[1,2^63-1]∩N是素数么. 按照朴素的判定素数方法,至少也需要O(P^0.5)的,但这道题就是霸气到连这样的时间复杂度都过不了的地步. 实在是不会做了,就学习了传说中的Miller-Rabin素数判定法. 两个引理: ①费马小定理: 设p为质数,且不满足p|a, 则a^(p-1)=a(mod p). 证: 又一个引理,若n与p互质,且a与p互质,则n*a与p互质. 这真的是一个看似很简单的引理,但它却意味着一些看似不那么简单的事情. 设A=(0,p)∩N,则 ①对

1702 素数判定 2

1702 素数判定 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 一个数,他是素数么? 设他为P满足(P<=263-1) 输入描述 Input Description P 输出描述 Output Description Yes|No 样例输入 Sample Input 2 样例输出 Sample Output Yes 数据范围及提示 Data Size & Hint 算法导论——数论那一节注意Carmich

素数判定相关资料

素数(质数)的判定 (1)最基本素数判定方法大家熟悉,只用看看2到n(或n的平方根)之间有没有n的约数: #include<stdio.h> void main() { int i,n; scanf("%d",&n); for(i=2;i<n;i++) if(n%i==0)break; if(i<n||n==1)puts("No"); else puts("Yes"); } 此方法适用于判定较少数,数据量大时会超时

1702 素数判定 2[[一中数论随堂练]

1702 素数判定 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 一个数,他是素数么? 设他为P满足(P<=263-1) 输入描述 Input Description P 输出描述 Output Description Yes|No 样例输入 Sample Input 2 样例输出 Sample Output Yes 数据范围及提示 Data Size & Hint 算法导论——数论那一节注意Carmich

HDU2012 素数判定

问题链接:HDU2012 素数判定. 这是个入门训练题,自然用C语言编写程序. 判定一个数是否为素数有各种各样的方法.参见:素性测试算法.这里采用比较简单的试除法来实现,并且将判断一个数是否为素数的功能封装到一个函数中. 本程序采用自顶向下逐步细化的编程方法,程序读起来逻辑清晰十分易懂. 使用带参数的宏定义,也是值得推荐的好方法. AC程序如下: /* HDU2012 素数判定 */ #include <stdio.h> #include <math.h> #define fun(