以下内容整理自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
, son 是一个素数
(下面的方法都是费马素数判定法的扩展) - 但是存在卡麦尔数会失败
- if
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 <<" ";
}
}
大家可以复制上述代码,从生成速度来说普通的确定性方法是很慢的,满足不了很多的要求