求奇素数的原根——C++实现

1.程序说明

输入:一个奇素数m

输出:按序输出m的所有原根

运行结果:

与课本样例进行对比:

2.实现思路

  • 判断是否与1模m同余

bool yi(double x, int m) {
	x -= 1;
	if (fmod(x,m) == 0) {
		return true;
	}
	else {
		return false;
	}
}//判断是否与1模m同余
  • 判断两个数是否互素

bool husu(int x,int m) {
	int i = 0;
	while (x != 0) {
		i = m % x;
		m = x;
		x = i;
	}
	if (m == 1) {
		return true;
	}
	return false;
}//判断是否x与m互素

即使用欧几里得辗转相除法求x和m的最大公因数是否为1,实现思路可以参考此博文

  • 实现素因子的分解

//以下用于求素因子分解
int n = oula;//记录欧拉函数值
int i = 2;
int num = 0;//用于计算有多少个不同的素因子
int a[100] = { 0 };
while (n != 1) {
	while (n % i == 0) {
		if (num == 0) {
			a[num] = i;
			num++;
		}
		else if (a[num-1] != i) {
			a[num] = i;
			num++;
		}
		n /= i;
	}
	i++;
}

使用了算术基本定理实现分解,可以参考此博文

  • 求出最小原根g

//以下为求最小原根
for (int i = 0; i < num; i++) {
	a[i] = oula / a[i];
}
int g = 2;
bool fail = true;
int j = 0;
while (fail) {
	for (j = 0; j < num; j++) {
		tem = pow(g, a[j]);
		if (yi(tem, m)) {
			break;
		}
	}
	if (j == num) {
		fail = false;//此时g即为最小原根
	}
	else {
		g++;
	}
}
  • 求出缩系,最终借助缩系求出所有原根

//以下为求缩系.
int* b = new int[oula];
int count = 0;//用于计算缩系中元素的个数
for (int i = 1; i < m; i++) {
	if (husu(i, oula)) {
		b[count] = i;
		count++;
	}
}

//最后,求所有原根
int *ans = new int[count];
for (int i = 0; i < count; i++) {
if (i == 0) {
		tem = pow(g, b[i]);
		ans[i] = fmod(tem, m);
	}
	else {
		ans[i] = ans[i - 1];
		for (int k = b[i - 1]; k < b[i]; k++) {
			ans[i] *= g;//这里简化计算,若直接求高次幂,容易因为精度不够产生错误。
		}
		ans[i] = fmod(ans[i], m);
	}
	cout << ans[i] << " ";
}
cout << endl;

3.完整代码

#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;

bool yi(double x, int m) {
	x -= 1;
	if (fmod(x,m) == 0) {
		return true;
	}
	else {
		return false;
	}
}//判断是否与1模m同余

bool husu(int x,int m) {
	int i = 0;
	while (x != 0) {
		i = m % x;
		m = x;
		x = i;
	}
	if (m == 1) {
		return true;
	}
	return false;
}//判断是否x与m互素

int main() {
	int m;
	cin >> m;
	double tem;
	int oula = m - 1;//m的欧拉函数

	//以下用于求素因子分解
	int n = oula;
	int i = 2;
	int num = 0;//用于计算有多少个不同的素因子
	int a[100] = { 0 };
	while (n != 1) {
		while (n % i == 0) {
			if (num == 0) {
				a[num] = i;
				num++;
			}
			else if (a[num-1] != i) {
				a[num] = i;
				num++;
			}
			n /= i;
		}
		i++;
	}

	//以下为求最小原根
	for (int i = 0; i < num; i++) {
		a[i] = oula / a[i];
	}
	int g = 2;
	bool fail = true;
	int j = 0;
	while (fail) {
		for (j = 0; j < num; j++) {
			tem = pow(g, a[j]);
			if (yi(tem, m)) {
				break;
			}
		}
		if (j == num) {
			fail = false;//此时g即为最小原根
		}
		else {
			g++;
		}
	}

	//以下为求缩系.
	int* b = new int[oula];
	int count = 0;//用于计算缩系中元素的个数
	for (int i = 1; i < m; i++) {
		if (husu(i, oula)) {
			b[count] = i;
			count++;
		}
	}

	//最后,求所有原根
	int *ans = new int[count];
	for (int i = 0; i < count; i++) {
		if (i == 0) {
			tem = pow(g, b[i]);
			ans[i] = fmod(tem, m);
		}
		else {
			ans[i] = ans[i - 1];
			for (int k = b[i - 1]; k < b[i]; k++) {
				ans[i] *= g;//这里简化计算,若直接求高次幂,容易因为精度不够产生错误。
			}
			ans[i] = fmod(ans[i], m);
		}
		cout << ans[i] << " ";
	}
	cout << endl;
	sort(ans, ans + count);//进行从小到大的排序
	cout << "所以," << m << "的所有原根为:(按从小到大排序)" << endl;
	for (int i = 0; i < count; i++) {
		cout << ans[i] << " ";
	}
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个 C++ 函数,它可以用于计算大素数原根: ``` #include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; // 判断一个数是否为素数 bool is_prime(int n) { if (n <= 1) { return false; } int sqr = sqrt(n); for (int i = 2; i <= sqr; i++) { if (n % i == 0) { return false; } } return true; } // 计算 a 的 b 次方对 p 取模的结果 int power_mod(int a, int b, int p) { int res = 1; while (b) { if (b & 1) { res = (long long)res * a % p; } a = (long long)a * a % p; b >>= 1; } return res; } // 获取大素数 p 的原根 int get_primitive_root(int p) { if (!is_prime(p)) { return -1; } vector<int> factors; int phi = p - 1; int tmp = phi; for (int i = 2; i <= tmp / i; i++) { if (tmp % i == 0) { factors.push_back(i); while (tmp % i == 0) { tmp /= i; } } } if (tmp > 1) { factors.push_back(tmp); } for (int g = 2; g <= p; g++) { bool flag = true; for (int i = 0; i < factors.size(); i++) { if (power_mod(g, phi / factors[i], p) == 1) { flag = false; break; } } if (flag) { return g; } } return -1; } int main() { int p; cout << "请输入一个大素数 p:" << endl; cin >> p; int g = get_primitive_root(p); if (g == -1) { cout << "无法找到 " << p << " 的原根!" << endl; } else { cout << p << " 的一个原根为:" << g << endl; } return 0; } ``` 该函数首先判断输入的 p 是否为素数,如果不是,则输出错误信息并返回 -1。接着,它将 p - 1 分解为质因数的积,并逐个尝试每个可能的原根。对于每个可能的原根 g,它计算 g 的 phi(p) / factors[i] 次方对 p 取模的结果,并检查是否等于 1。如果对于所有质因子 i,g 的 phi(p) / factors[i] 次方对 p 取模的结果都不等于 1,则 g 是 p 的原根。如果无法找到 p 的原根,则输出错误信息并返回 -1。 注意,计算原根的时间复杂度为 O(p log^2 p),因此该函数对于较大的素数可能需要较长的计算时间。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hyper OS

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

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

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

打赏作者

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

抵扣说明:

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

余额充值