#include<iostream>
#include<fstream>
#include<string>
#include<algorithm>
using namespace std;
const int maxn = 50;
const int MAXN = 10000000;
int prime[maxn]; // 模数的质因子
int e[maxn]; // 判别因子
int cnt = 0; // 模数的质因子数,也等于判别因子数
int bcode[maxn][maxn]; // 判别因子的二进制数,第一个元素记录二进数长度
int srs[MAXN]; // 简化剩余系(Simplified residual system)
int answer[MAXN];
ofstream OutFile;
int euler_phi(int n) {
int m = (int)sqrt(n + 0.5);
int ans = n;
for (register int i = 2; i <= m; i++)
if (n%i == 0)
{//最好要先除后乘,防止结果溢出
ans = ans / i * (i - 1);
while (n%i == 0)n = n / i;//将n中所有因子i筛去
//确保下一个i是n的质因子
}
if (n > 1)ans = ans / n * (n - 1);//防止n为最后一个质因子
return ans;
}
int partition(int n, int* prime) //分解模因数,并求出该模下的原根判别因子
{
int num = n;
int cnt = 0;
for (int i = 2; i <= sqrt(n); i++)
if (num%i == 0)
{
prime[cnt++] = i;
while (num%i == 0)
num /= i;
}
for (int i = 0; i < cnt; i++) //求判别因子
e[i] = n / prime[i];
return cnt;
}
void genbcode(int n, int bcode[][50]) //生成判别因子的二进制数,此处注意二维数组传参
{
for (int i = 0; i < n; i++)
{
int k = 0;
int num = e[i];
while (num)
{
bcode[i][++k] = num & 1;
num = num >> 1;
}
bcode[i][0] = k;
}
}
int powerMod(int e, int b, int m) //e为指数
{
int a = 1;
int i, k = 0, num = e;
/*计算指数的二进制位数k.*/
while (num)
{
num = num >> 1;
++k;
}
for (i = 0; i < k; ++i)
{
// 取e的二进制的第i位,判断是否为1.
if ((e >> i) & 1)
a = a * b %m;
b = b * b %m;
}
return a;
}
int powerMod(int* p, int b, int n, int m) // 模重复平方算法,*p存储一个数的二进制数,n为p中的元素数,b为底数,m为模
{
int a = 1;
for (int i = 1; i <= n; ++i)
{
if (p[i])
a = a * b %m;
b = b * b %m;
}
return a;
}
bool judge(int b, int m) // 判断b是否为模p的原根
{
for (int i = 0; i < cnt; i++)
if (powerMod(bcode[i], b, bcode[i][0], m) == 1) return false;
return true;
}
int PR(int m) //求m的原根
{
cnt = partition(euler_phi(m), prime);
genbcode(cnt, bcode);
int b = 1;
while (!judge(++b, m));
return b;
}
//int squarePR(int m) //求m^2的原根
//{
// int pr = PR(m);
// if (powerMod(m - 1, pr, m*m) == 1) return pr + m; // pr表示初始的原根,此处有定理:pr+m或pr为m^2的原根
// return pr;
//}
void SRS(int n, int* srs) //求n的简化剩余系,存储在srs[]中
{
for (int i = 0; i < cnt; i++)
{
int j = 1;
while (prime[i] * j <= n)
{
srs[prime[i] * j] = 1; //删去质因数的倍数
j++;
}
}
}
int findAll(int pr, int m)//找到m的所有原根
{
int total = 0;
SRS(euler_phi(m), srs);
for (int i = 1; i <= euler_phi(m); i++) if (!srs[i])
{
int arr[maxn], k = 0, num = i;
while (num)
{
arr[++k] = num & 1;
num = num >> 1;
}
answer[total++] = powerMod(arr, pr, k, m*m);
}
sort(answer, answer + total);
return total;
}
int main()
{
int m, ans;
cout << "输入模数:";
cin >> m;
int pr = PR(m); //求出初值
cout << pr << "是模" << m << "的原根" << endl;
prime[cnt++] = m;
OutFile.open("result.txt");
ans = findAll(pr, m);
OutFile << "一共有" << ans << "个原根" << endl;
for (int i = 0; i < ans; i++)
{
if (i % 10 == 0 && i) OutFile << endl;
OutFile << answer[i] << '\t';
}
OutFile.close();
system("pause");
}
参考