Miller-Rabin随机性素数测试方法 [CodeVS 1702] 素数判定2

2023-10-20 20:08

本文主要是介绍Miller-Rabin随机性素数测试方法 [CodeVS 1702] 素数判定2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Miller-Rabin算法用于判定某数x是否为素数。如果x被判定为合数,它一定是合数。如果x被判定为素数,它有很大的概率是素数,此概率取决于参数。

费马小定理:
如果n为素数,那么对于任意与n互质的a,有

an11(modn)     ()

如果a与n不互质,上式一定不成立。因为它意味着 aan21(modn) ,而a存在模n的乘法逆元当且仅当a, n互质。

如果对于某个a,合数n满足(*)式,那么称n为一个基为a的伪素数。如341是基为2的伪素数。

如果某个合数n对于任意与n互质的a都有(*)式成立,那么称n为Carmichael数。前3个Carmichael数是561, 1105和1729。我们也许会想随机几个a,如果碰到一个与n不互质的基数,就能正确检验了,然而如果n只有大素数因子,这样的基数a很难找到。

只有22个小于10000的基为2的伪素数,只有255个小于100000000的Carmichael数。直接上费马小定理,在实际应用中是可行的,在算法竞赛等领域是不可行的。

Miller-Rabin算法有效地降低了出错的概率。这个概率取决于参数,与被测试的数无关。

设n是待测试的大于1的整数,决定精确程度的参数为s,Miller-Rabin算法的伪代码如下:

Miller-Rabin(n, s)特判n为偶数的情形计算t, u使得n-1=2^t*u且u是奇数,即,t是n-1的二进制表示中末尾0的个数,u是去掉这些0后得到的数for i=1 to s令a为(1, n)内的随机整数x = a^u mod nfor j=1 to t and x != 1y = x*x mod nif y == 1 and x != n-1 // x是以n为模1的非平凡平方根 => n是合数return Compositey = xif x != 1 // a^(n-1) != 1 => n是合数return Compositereturn Prime // 通过素性测试 => n有至少(1-2^(-s))的概率为素数

框架来自《算法导论》,我在不改变算法行为的前提下做了一点改进。

关于算法原理的两点说明:
1) p是奇素数=> x21(modp) 仅有两平凡解 x±1
证明:方程等价于 (x+1)(x1)0(modp) ,由于p是素数,必有p整除(x+1)或(x-1)。p整除(x+1) <=> x1 ,p整除(x-1) <=> x1 。由于p是大于2的奇数, 11 。证毕。
由此,当n>1, x21(modn) 有非平凡解=>n不是奇素数。又,当n=2时,仅有一个平凡解 x1 ,所以n也不是偶素数。n是合数。

2) 可以证明:在运用原理1)的条件下,如果n是一个奇合数,则n为合数的证据数目至少为(n-1)/2。证据是指判定n为合数的基底a。于是,在[1, n)共(n-1)个数内随机挑选一个,得到证据的概率至少为1/2。把合数误判为素数意味着s次循环都能没找到证据,概率为2^(-s)。

一本由林厚从主编、王宏主审、东南大学出版社出版的《信息学奥赛之数学一本通》告诉我们,最好只生成奇数,以省去原理1)的使用,“进一步提高测试速度”,这当然是错误的。

关于算法实现的两点说明:
1) 计算x = a^u mod n可使用快速幂,整个算法的时间复杂度为 O(slgn) 。两个long long类型的数相乘并取模,尽管得到一个long long类型的数,但在相乘的那步就溢出了。解决方案一是采用快速加/快速乘/快速模/慢速模,它们是同一个东西,你懂的。解决方案二是像骆可强《论程序底层优化的一些方法与技巧》一文中提到的那样,借助于浮点运算和最终答案在long long范围内的事实(其实我也没完全理解,暂且当作一个trick记住吧),特判负数是由于对浮点运算四舍五入。

2) 《算法导论》中说,对几乎所有可以想象到的应用,选取s=50应该是足够的。

CodeVS 1702 素数判定2

#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long ll;
const int s = 10;inline ll mul_mod(ll a, ll b, ll n)
{ll c = a*b-(ll)((long double)a*b/n+0.5)*n;return c<0 ? c+n : c;
}ll fast_exp(ll a, ll x, ll n)
{ll b = 1;while (x) {if (x & 1)b = mul_mod(b, a, n);a = mul_mod(a, a, n);x >>= 1;}return b;
}bool MR(ll n)
{if (!(n&1))return n == 2;ll t = 0, u;for (u = n-1; !(u&1); u >>= 1)++t;for (int i = 0; i < s; ++i) {ll a = rand()%(n-2)+2, x = fast_exp(a, u, n);for (ll j = 0, y; x != 1 && j < t; ++j, x = y) {y = mul_mod(x, x, n);if (y == 1 && x != n-1)return false;}if (x != 1)return false;}return true;
}int main()
{srand(time(0));ll p;scanf("%lld", &p);puts(MR(p) ? "Yes" : "No");return 0;
}

这篇关于Miller-Rabin随机性素数测试方法 [CodeVS 1702] 素数判定2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/249429

相关文章

poj 1127 线段相交的判定

题意: 有n根木棍,每根的端点坐标分别是 px, py, qx, qy。 判断每对木棍是否相连,当他们之间有公共点时,就认为他们相连。 并且通过相连的木棍相连的木棍也是相连的。 解析: 线段相交的判定。 首先,模板中的线段相交是不判端点的,所以要加一个端点在直线上的判定; 然后,端点在直线上的判定这个函数是不判定两个端点是同一个端点的情况的,所以要加是否端点相等的判断。 最后

开关电源纹波测试方法

开关电源纹波测试是评估开关电源性能的重要手段,我们都知道开关电源中稳定的输出电压是交流电通过整流、稳压、滤波等处理后得到的稳定输出,虽然经过了处理,但直流电平上还是会有周期性和随机性的杂波信号,这些我们不需要的部分就是纹波。开关电源中存在纹波是无法避免的,因此在开关电源测试中输出纹波的测试必不可少。 以下是开关电源纹波测试的具体方法和步骤: 测试方法 开关电源纹波测试一般

js算法判断是否为素数

/*判断一个数字是否是质数: 质数(prime number)又称素数,有无限个。除了1和它本身以外不再被其他的除数整除。*/ function isPrime(number){ //判断输入是否为number类型,是否为整数       if (typeof number!=='number'||!Number.isInteger(number))      {

Hessian矩阵判定极值之MATLAB实现符号解

By WC 1.9 .2015 1.Hessian矩阵 其定义如下: 如果函数f在D区域内二阶连续可导,那么黑塞矩阵H(f) 在 D 内为对称矩阵。原因是:如果函数f连续,则二阶偏导数的求

【时时三省】c语言例题----华为机试题< 查找组成一个偶数最接近的两个素数>

山不在高,有仙则名。水不在深,有龙则灵。                                                                         ----CSDN 时时三省 1,题目 HJ60 查找组成一个偶数最接近的两个素数 描述 任意一个偶数(大于2)都可以由2个素数组成,组成偶数的2个素数有很多种情况,本题目要求输出组成指定偶数的两个

题目:求100以内的素数,全部打印出来。

题目:求100以内的素数,全部打印出来。 public class ZhaoSuShu {public static void isPrime1(){int i,j,count = 0;//System.out.println("2");for(i = 1; i <= 100; i++){for(j = 2; j <= i; j++){if(i % j == 0){break;}}if(j ==

素数判定和分解质素数

1.素数判定   public static boolean isPrime(int n) {if (n <= 1) return false;if (n == 2) return true;if (n % 2 == 0) return false;int limit = (int)Math.sqrt(n) + 1;for (int i = 3; i <= limit; i += 2) {i

Java-计算素数

判断输入的数字是不是素数: public class SuShu{public static void main(String[] args){java.util.Scanner s=new java.util.Scanner(System.in);int i=s.nextInt();boolean isSuShu=true; //标记;for(int j=2;j<i;j++){if(i%j=

常见素数筛法

列出几种常用的素数筛选法,附上计时器。。。 #include<cstdio>#include<cstdlib>#include<cmath>#include<map>#include<queue>#include<stack>#include<vector>#include<algorithm>#include<cstring>#include<string>#inclu

【编程基础C++】素数判定、最小公倍数与最大公因数的实现方法

文章目录 素数法一法二 最大公因数辗转相除法另一写法 最小公倍数直接枚举法根据GCD算LCM 素数 素数 是指大于1的自然数,且只能被1和自身整除。例如,2、3、5和7都是素数。它们在数学中非常重要,因为任何大于1的自然数都可以唯一地表示为素数的乘积,这被称为素数分解。 法一 #include <iostream>using namespace std;bool IsPr