单变量线性同余方程的C++实现

在这里要注意一点的就是乘法逆的求法:

求a关于n的乘法逆的方法就是利用扩展的欧几里得算法求解:

s * n + a * t = 1 (gcd(n,a) = 1才存在乘法逆)

实现代码如下:

int gcd(int x,int y){  
    return y == 0 ? x : gcd(y,x%y);   
}   
void exEuclidean(int a,int b,int &s,int &t){  
    int r1 = a, r2 = b , s1 = 1, s2 = 0, t1 = 0, t2 = 1;//初始化  
    int q,r;   
    while(r2 > 0)  
    {  
        q = r1 / r2;  
  
        r = r1 - q * r2; //也就是r = r1%r2;  
        r1 = r2;  
        r2 = r;  
  
        s = s1 - q * s2;  
        s1 = s2;  
        s2 = s;  
        
        t = t1 - q * t2;  
        t1 = t2;  
        t2 = t;   
    }  
    //gcd(a,b) = r1;   
    s = s1;   
    t = t1;  
}  
int main()
{
	int a,n,b;
	printf("请依次输入ax %% n = b方程中的系数 a , n ,b!\n");
	//其实就是ax = kn + b ,也就是 ax + nk = b-------线性丢番图方程 
	scanf("%d %d %d",&a,&n,&b);
	int gcd_a_n = gcd(a,n);
	if(b%gcd_a_n != 0){
		//根据线性丢番图方程 ax + by = c中如果gcd(a,b)不能整除c的话,无解 
		printf("gcd(a,n)不能整出b,该方程无解\n");
	}
	else{ //有解 
		//(1)除以gcd_a_n,简化方程 
		a /= gcd_a_n;
		n /= gcd_a_n;
		b /= gcd_a_n; 
		
		//(2)乘以a的乘法逆,找出方程特解x0
		//利用扩展的欧几里得算法求 n * s + a * t = 1(注意:1是n和a的gcd)   
        int s,t;  
        exEuclidean(n,a,s,t); //因为传引用,s和t得到解了 
        int a_ = (t >= 0) ? (t % n) : ((t-t*n)%n); //乘法逆就是t映射于n的值 
        int x0 = (b*a_)%n;
        printf("特解是%d\n",x0);
		 
		//(3)得到所有的通解 
		printf("通解是 x0 + k * %d , 0 <= k < %d\n",n,gcd_a_n);
		printf("所有的通解为:\n");
		vector ans;
		for(int i = 0 ; i < gcd_a_n; i++){
			ans.push_back(x0 + i * n);
			printf("%d ",ans[i]);
		}
		printf("\n");
	}
}

运行结果如下:

单变量线性同余方程的C++实现_第1张图片

你可能感兴趣的:(密码学)