HDU2138(Miller-Rabin素数检测)

最近在看RSA,找到一个一个大素数是好多加密算法的关键一步,而大素数无法直接构造,一般情况下都是生成一个随机数然后判断是不是素数。判断是否是素数的方法有好多,有的能够准确判断,比如可以直接因式分解(RSA的安全性就基于这是困难的),速度稍微快一点的对素数又有特殊要求,而Miller-Rabin素数检测法可以在一定概率上认为一个数是素数,以极小概率的错误换取时间。Miller-Rabin算法基于一个数如果是素数就满足费马小定理,即a^(n-1) ≡1(mod n),而如果满足此现象却不是素数就成为基于a的伪素数(Carmichael)数,Carmichael数是非常少的。在1~100000000范围内的整数中,只有255个Carmichael数。Miller-Rabin使用多个随机生成的a进行检测就可以将错误率降低到相当低,并且在每次计算模取幂时如果发现对模n来说1的非平凡平方根,就可以提前判断n为素数了。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define S 50

int miller_rabin(int n,int s);
bool witness(long long base,long long n);

int main()
{
	int m;
	while(scanf("%d",&m) != EOF){
		int n,cnt = 0;

		for(int i = 0;i < m;i++){
			scanf("%d",&n);

			if(n % 2 == 0){
				cnt += (n == 2);
			}
			else{
				cnt += miller_rabin(n,S);
			}
		}

		printf("%d\n",cnt);
	}

	return 0;
}

int miller_rabin(int n,int s)
{
	for(int i = 0;i < s && i < n;i++){
		long long base = rand() % (n - 1) + 1;

		if(witness(base,n)){
			return 0;	
		}
	}

	return 1;
}

bool witness(long long base,long long n)
{
	int len = ceil(log(n - 1.0) / log(2.0)) - 1; 
	long long x0 = 0,x1 = 1;

	for(int i = len;i >= 0;i--){
		x0 = x1;
		x1 = (x1 * x1) % n;

		if(x1 == 1 && x0 != 1 && x0 != n - 1){
			return true;
		}
		if(((n - 1) & (1 << i)) > 0){
			x1 = (x1 * base) % n;
		}
	}
	return x1 != 1;
}

//10902607	2014-06-23 23:34:23	Accepted	2138	125MS	228K	946 B	G++	超级旅行者


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值