中国剩余定理的算法实现(基于c语言miracl库)

某电信安数基实验
在这里插入图片描述
要求:三个(老师要求的)方程组成的一次同余方程,文件中大数的顺序依次为a1,a2,a3,m1,m2,m3
在这里插入图片描述
函数:

multiply
函数原型: void multiply(big x, big y, big z);
功能说明: 两个大数相乘,z=x*y。

fdiv
函数原型:void fdiv(x,y,z);
功能说明:将两个大数相除,z=x/y。

xgcd
函数原型: int xgcd(bigx, big y, big xd, big yd, big z);
功能说明: 计算两个大数的扩展最大公约数,也可以用来计算模逆。这个实验我们是用它来计算模逆。
例子: xgcd(x,p,x,x,x); //计算x^-1 mod p
/* x = 1/x mod p (p is prime) */

add
函数原型: void add(big x, big y, big z);
功能说明: 两个大数相加,z=x+y。
Example: add(x,x,x); // This doubles the value of x.

powmod
函数原型: void powmod(big x, big y,big z, big w);
功能说明: 模幂运算,w=xy(modz)。

cinstr
函数原型: int cinstr(big x, char*s);
功能说明: 将大数字符串转换成大数
返回值: 输入字符数的个数

egcd(x, y, z);//求最大公约数g=(x,y)

直接贴代码啦

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include "miracl.h"
#include<Windows.h>

int main()
{
	FILE *fp;
	char fpname[100];//文件名
	int i, j, k;//备用
	char ch, datachar[7][500];//datachar为字符型的大数,使用7是为了防止最后一个换行符导致的数组越界
	miracl *mip = mirsys(500, 10);
	big a1 = mirvar(0);
	big a2 = mirvar(0);
	big a3 = mirvar(0);
	big m1 = mirvar(0);
	big m2 = mirvar(0);
	big m3 = mirvar(0);
	big m = mirvar(0);
	big Mi1 = mirvar(0);//为M1,M2,M3
	big Mi2 = mirvar(0);
	big Mi3 = mirvar(0);
	big Mj1 = mirvar(0);//为M1,M2,M3各自的逆
	big Mj2 = mirvar(0);
	big Mj3 = mirvar(0);
	big g1 = mirvar(0);//g1,g2,g3先用于判断m1,m2,m3是否互素,而后用于计算g = Mi*Mj*a 和 最后加法运算的中间变量
	big g2 = mirvar(0);
	big g3 = mirvar(0);
	big one = mirvar(1);//one=1

	printf("输入文件完整路径\n");
	scanf("%s", fpname);
	if ((fp = fopen(fpname, "r")) == NULL)
	{
		printf("fail to open the file\n");
		system("pause");
		exit(0);
	}
	else
	{
		i = 0; j = 0;
		while (!feof(fp))
		{
			fscanf(fp, "%c", &ch);//从文件中读入一个字符
			if (ch == '\n')
			{
				datachar[i][j] = '\0';//datacha[i][]输入完毕
				i++; j = 0; continue;//开始输入下一个数
			}
			datachar[i][j] = ch;
			j++;
		}
		datachar[i][j-1] = '\0';//datacha[i][]输入完毕,使用\0结尾
		//文件录入结束

		//把字符串转化为big型大数
		cinstr(a1, datachar[0]);
		cinstr(a2, datachar[1]);
		cinstr(a3, datachar[2]);
		cinstr(m1, datachar[3]);
		cinstr(m2, datachar[4]);
		cinstr(m3, datachar[5]);

		//判断mm1,m2,m3是否互素
		egcd(m1, m2, g1);//求最大公约数
		egcd(m2, m3, g2);
		egcd(m3, m1, g3);
		if (!((compare(g1, one) == 0) && (compare(g2, one) == 0) && (compare(g3, one)==0)))//当最大公约数都为1的时候,两两互素,则不进入if语句
		{
			printf("三个m并不两两互素,不能直接使用中国剩余定理\n");
			//结束
		}
		else {

			multiply(m1, m2, m);
			multiply(m, m3, m);//计算m=m1*m2*m3

			fdiv(m, m1, Mi1);//计算Mi1
			fdiv(m, m2, Mi2);//计算Mi2
			fdiv(m, m3, Mi3);//计算Mi3

			xgcd(Mi1, m1, Mj1, Mj1, Mj1);//Mj1为Mi1的逆
			xgcd(Mi2, m2, Mj2, Mj2, Mj2);//Mj2为Mi2的逆
			xgcd(Mi3, m3, Mj3, Mj3, Mj3);//Mj3为Mi3的逆

			multiply(Mi1, Mj1, g1);
			multiply(g1, a1, g1);//g1=Mi1*Mj1*a1

			multiply(Mi2, Mj2, g2);
			multiply(g2, a2, g2);//g2=Mi2*Mj2*a2

			multiply(Mi3, Mj3, g3);
			multiply(g3, a3, g3);//g3=Mi3*Mj3*a3

			/*cotnum(g1, stdout);
			cotnum(g2, stdout);
			cotnum(g3, stdout);*/

			add(g1, g2, g1);//g1 = Mi1*Mj1*a1+Mi2*Mj2*a2
			add(g1, g3, g1);//g1 = Mi1*Mj1*a1+Mi2*Mj2*a2+Mi3*Mj3*a3
			powmod(g1, one, m, g1);// g1 = g1的一次方 mod m

			printf("\n");
			printf("X is : \n");
			cotnum(g1, stdout);
			printf("m is : \n");
			cotnum(m, stdout);
			printf("\n");
			//即 X ≡ g1 ( mod m )
		}
	}
	fclose(fp);
	mirexit();
	system("pause");
}
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
#include #include using namespace std; typedef int LL; typedef pair PLL; LL inv(LL t, LL p) {//求t关于p的逆元 if (t >= p) t = t%p; return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p; } LL gcd(LL a, LL b){ return b == 0 ? a : gcd(b, a%b); } PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组 LL x = 0, m = 1; for (int i = 0; i < n; i++) { LL a = A[i] * m, b = B[i] - A[i] * x, d =gcd(M[i], a); if (b % d != 0) return PLL(0, -1);//答案不存在,返回-1 LL t = b / d * inv(a / d, M[i] / d) % (M[i] / d); x = x + m*t; m *= M[i] / d; } x = (x % m + m) % m; return PLL(x, m);//返回的x就是答案,m是最后的lcm值 } int main() { int n; scanf_s("%d", &n); LL a[2017], b[2017], m[2017]; for (int i = 0; i<n; i++) { scanf_s("%d%d%d", &a[i], &b[i], &m[i]); } PLL pa = linear(a, b, m, n); printf("%lld\n", pa.first); } 设计思路: 有这样一道算术题:“今有物不知其,三三之剩二,五五之剩三,七七之剩二,问物几何?” 解这题,先构造一个答案 5*7*inv(5*7, 3) % 3 = 1 3*7*inv(3*7, 5) % 5 = 1 3*5*inv(3*5, 7) % 7 = 1 然后两边同乘你需要的 2 * 5*7*inv(5*7, 3) % 3 = 2 3 * 3*7*inv(3*7, 5) % 5 = 3 2 * 3*5*inv(3*5, 7) % 7 = 2 令 a = 2 * 5*7*inv(5*7, 3) b = 3 * 3*7*inv(3*7, 5) c = 2 * 3*5*inv(3*5, 7) 那么 a % 3 = 2 b % 5 = 3 c % 7 = 2 其实答案就是a+b+c 因为 a%5 = a%7 = 0 因为a是5的倍,也是7的倍 b%3 = b%7 = 0 因为b是3的倍,也是7的倍 c%3 = c%5 = 0 因为c是3的倍,也是5的倍 所以 (a + b + c) % 3 = (a % 3) + (b % 3) + (c % 3) = 2 + 0 + 0 = 2 (a + b + c) % 5 = (a % 5) + (b % 5) + (c % 5) = 0 + 3 + 0 = 3 (a + b + c) % 7 = (a % 7) + (b % 7) + (c % 7) = 0 + 0 + 2 = 2 答案a+b+c完全满足题意 但是答案,不只一个,有无穷个,每相隔105就是一个答案(105 = 3 * 5 * 7) a=2*5*7*2=140 b=3*3*7*1=63 c=2*3*5*1=30 140+63+30=233 2335 = 23 如果题目问你最小的那个答案,那就是23了。 当 1*x=2(%3) 1*x=3(%5) 1*x=2(%7) 输入: 3 1 2 3 1 3 5 1 2 7 输出: 23

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值