那些年关于素数的算法:素数判断方法分类 及 试除法, 费马素数,米勒-拉宾代码实现

以下内容整理自wiki


素数(质数)
大于1的自然数中,除1与其本身外,无法被其他自然数整数的数
注:其余的就是合数,1两者都不是

先知: 两个整数a,b,若它们除以正整数 m所得的余数相等,则称a, b对于模m同余,记为:a≡b(mod m)
理论知识

一丶素数测试:检验是否为素数

  • 确定性测试:一般比较慢,总能测试出一个数是否为素数还是合数,有如下方法

    • 试除法:逐一测试2~√n,确保无一能被整除
    • 筛选法:这个是没有计算机常用的,已知某个数一下的所有素数,然后跟里面对比筛选,就知道是不是了
    • 椭圆曲线素数证明
    • AKS素数测试 :这个定理是费马小定理的一般化,整数n为质数,当且仅当(x+a)n ≡(xn+a)(mod n)
  • 随机性测试:一般比较快,但无法完全证明一个数是否为素数。这类测试依靠部分随机的方法来测试一个给定的数字。例如,一测试在应用于素数时总是会通过,但在应用于合数时通过的概率为 p。若重复这个测试n次,且每次都通过,则该数为合数的概率为1/(1-p)n,会随着测试次数呈指数下滑,因此可越来越确信(虽然总是无法完全确信)该数为素数。另一方面,且一旦测试曾失败过,则可知该数为合数。有如下方法
    在这里插入图片描述

    • 费马素数判定法
      • if 1≤a≤n-1都有 an ≡a (mod n) ,也就是 an-1 mod n = 1, so n 是一个素数(下面的方法都是费马素数判定法的扩展)
      • 但是存在卡麦尔数会失败
    • Solovay-Strassen素性测试
    • 贝利-PSW测试
    • 米勒-拉宾测试:现在很常用的
      在这里插入图片描述

试除法,费马素数,米勒-拉宾代码

#include <iostream>
using namespace std;
typedef unsigned long long ll;

ll* d2t(ll num) //10进制转为2进制
{
	ll *temp = new ll[100];
	int b_num = 0;
	do
	{
		temp[b_num] = num % 2;  //存取的 0-n  代表低-高
		num = (num - temp[b_num]) / 2;
		b_num++;
	} while (num);
	temp[b_num] = 2; // 加入结束符号2 检测时遇到2就结束
	return temp;
}
int returnsize(ll *temp)  //检验数量
{
	int num = 0;
	while (temp[num++] != 2);
	return num - 1;
}

ll getmodpow(ll base, ll  *binary,int m, int num) //计算模幂
{
	ll result = 1;
	for (int i = 0; i < num; i++)
	{
		if (binary[i])
			result = (result * base) % m;
		base = (base*base) % m;

	}
	return result;
}
ll powR(int base ,int num)  // n-1 转化为 2^s *d
{
	for (int i = 1; i <= num; i++)
		base *= base;
	return base;
}

void parse(ll num,int *d,int *s)
{

	int temp=num;
	temp = num % 2;
	if(temp == 0)
	{
		while (temp == 0)
		{
			num = num / 2;
			*s = *s + 1; //不可以*s++
			temp = num % 2;

		}
		*d = num;
		*s = *s - 1;
	}
	else
	{
		*d = num;
		*s = 1;
	}
}	

bool MillerRabindetect(int num) //米勒-拉宾测试
{
	int d = 1; int s = 1;
	parse(num - 1, &d, &s);
	int repeatsize = 20;
	while (repeatsize--)
	{ 
		int r;
		ll base = rand() % (num -2-2+1) + 2;
		ll *pow = d2t(d);
		int size = returnsize(pow);
		int x= getmodpow(base, pow, num, size);
		if (x == 1 || x == num - 1) continue;
		for ( r = 1; r < s; r++)
		{
			 x = getmodpow(x, d2t(2), num, 2);
			if (x == num - 1) { r = s+1; }				
		}
		if (r == s) return false; 
	}
	return true;
}
bool Fermatdetect(int num) //费马素数判定法
{
	
	//在[1, n − 1]范围内随机选取a
	//如果a^n − 1 mod n ≠ 1那么返回合数
	int repeatsize = 20;
	while (repeatsize--)
	{
		ll a = rand() % (num - 1) + 1;
		ll *pow = d2t(num - 1);
		int size = returnsize(pow);
		if (getmodpow(a, pow, num, size) != 1) return false;
	}
	return true;
}

bool normal(int n)  //试除法
{
	int i, flag = 0;
	for (i = 2; i <= n / 2; ++i)
	{
		// 符合该条件不是素数
		if (n%i == 0)
		{
			flag = 1;
			break;
		}
	}
	if (flag == 0)
		return true;
	else
		return false;
}
int main()
{
	
	cout << "Normal" << endl;
	for (ll i = 468900100; i < 468900200; i++)
	{
		if (normal(i))
			cout << i <<" ";
	}
	cout << endl;
	cout << "Fermatdetect" << endl;
	for(ll i= 468900100;i< 468900200;i++)
	{ 
		if (Fermatdetect(i))
			cout << i<<" ";
	}
	cout << endl;
	cout << "MillerRabindetect" << endl;
	for (ll i = 468900100; i < 468900200; i++)
	{
		if (MillerRabindetect(i))
			cout << i <<" ";
	}
}

在这里插入图片描述

大家可以复制上述代码,从生成速度来说普通的确定性方法是很慢的,满足不了很多的要求


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yilyil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值