大数的模指数运算

在本文中我们将采用重复平方乘算法,即如图1:
重复平方乘算法
来解决类似于求a^e mod m的值的问题(a、e、m的位数均可以达到1024位,即计算机无法直接用基本数据类型存储的数据),在代码中一共有6个函数:
第一个为大数减法函数,第二个为大数除法函数,第三个为大数除法函数中的判断辅助函数,第四个为十进制转换为二进制函数,第五个为大数平方函数,第六个为大数乘法函数,有返回值的函数的返回值均是操作数组运算后的位数,代码如下:

#include<stdio.h>
#include<string.h>

int digit;
int a[1024],e[1024],m[1024],b[1024];       //程序操作使用的整数数组 
char S_a[1024],S_e[1024],S_m[1024];     //由用户输入的底数、指数、模数 

void BigSubtract(int x[],int y[],int len1,int len2);
int BigDivision(int x[],int y[],int len1,int len2);
int judge(int x[],int y[],int len1,int len2);
int Decimal_To_Binary(int e[],int e_length);
int BigSquare(int a[],int a_length);
int BigMult(int a[],int b[],int a_length,int b_length);

 int main(){
 	int i,j;
 	printf("请先输入操作数(底数)a:");
	scanf("%s",S_a);
	printf("请先输入操作数(指数)e:");
	scanf("%s",S_e);
	printf("请先输入操作数(模数)m:");
    scanf("%s",S_m);
    int a_length=strlen(S_a);
    int e_length=strlen(S_e);
    int m_length=strlen(S_m);
    int b_length;
    
    for(j=0,i=a_length-1;i>=0;i--,j++) 
		a[j]=S_a[i]-'0';
	for(j=0,i=e_length-1;i>=0;i--,j++) 
		e[j]=S_e[i]-'0';
    for(j=0,i=m_length-1;i>=0;i--,j++) 
		m[j]=S_m[i]-'0';
	
	printf("用户输入的底数a为:");	          //人性化提示用户输入的数据是否正确 
	for(j=a_length-1;j>=0;j--) 
		printf("%d",a[j]);
    printf("\n");
    
    printf("用户输入的指数e为:");	         //人性化提示用户输入的数据是否正确
	for(j=e_length-1;j>=0;j--) 
		printf("%d",e[j]);
    printf("\n");
    
    printf("用户输入的模数m为:");	         //人性化提示用户输入的数据是否正确
	for(j=m_length-1;j>=0;j--) 
		printf("%d",m[j]);
    printf("\n");
				
	int eBinaryLength=Decimal_To_Binary(e,e_length);  //得到转换为二进制后的数组长度 
	
    printf("指数的二进制表示:");             //将指数的二进制数组输出屏幕,以便检验数据是否正确 
	for(i=eBinaryLength-1;i>=0;i--)
	printf("%d",e[i]);
	printf("\n"); 
		   
    if (e[0]==0)                       //初始化需要进行持续操作的A数组和B数组 
    {
       for(i=1;i<1024;i++)
	   b[i]=0;
	   b[0]=1;
	   b_length=1;
    }
    else
	{
	   for(i=0;i<1024;i++)
	   b[i]=a[i];
	   b_length=a_length;
    }
    
 for(j=1;j<eBinaryLength;j++)                 //以二进制数组的长度为循环,进行对应的操作 
 {
	 a_length=BigSquare(a,a_length);
	 a_length=BigDivision(a,m,a_length,m_length);	     //计算A数组平方再模M数组后的数值 
     if(e[j]==1)
     b_length=BigMult(a,b,a_length,b_length);           //如果当前二进制数位为1,则对B数组进行相应的初始化 
     b_length=BigDivision(b,m,b_length,m_length);
 }
   printf("用户输入的数据的模运算结果为:");            //打出实验结果 
   for(i=b_length-1;i>=0;i--)  
	     printf("%d",b[i]);
}

//大数乘法运算 
int BigMult(int a[],int b[],int a_length,int b_length){
 	int i,j,temp;
	int a1[1024];
    for(i=0;i<=1024;i++)
	    a1[i]=0;
    for(i=0;i<a_length;i++)                 //进行乘法运算 
	  for(j=0;j<b_length;j++)          
	      a1[i+j]+=a[i]*b[j];
	  for(i=0;i<1024;i++)
	  {
	  	temp=a1[i];
	  	a1[i]=(temp%10);
	  	a1[i+1]+=(temp/10);
	  }
	  for(i=0;i<1024;i++)
	     b[i]=a1[i];
	  for(i=1023;i>=0;i--)                  //计算B数组的数位 
	     if(b[i])
	       break;
	 return i+1; 
 }
 
//大数平方乘运算 
int BigSquare(int a[],int len1){
	  int i,j,temp;
	  int a1[1024];
	  for(i=0;i<1024;i++)
	    a1[i]=0;
	  for(i=0;i<len1;i++)                    //平方乘 
	    for(j=0;j<len1;j++)
	      a1[i+j]+=(a[i]*a[j]);
	  for(i=0;i<1024;i++)
	  {
	  	temp=a1[i];
	  	a1[i]=(temp%10);
	  	a1[i+1]+=(temp/10);
	  }
	  for(i=0;i<1024;i++)
	     a[i]=a1[i];
	  for(i=1023;i>=0;i--)                  //计算A数组的数位 
	     if(a[i]!=0)
	       break;
	 return i+1;        
}
 
//十进制转换为二进制
int Decimal_To_Binary(int e[],int e_length){
	int m[1024];
	int j=0;
	int i=0;
	for(i=0;i<e_length;i++){
		if(e[i]){
			m[j]=e[0]%2;
			j++;
			for(i=0;i<e_length-1;i++)                  //转换二进制操作 
			{
			   e[i]=((e[i+1]%2)*10+e[i])/2;
			}
		 	   e[e_length-1]=e[e_length-1]/2;
		    for(i=e_length-1;i>=0;i--)
		    {  
		       if(i=0&&e[i]==0)
		       goto next;	
	        }
	 }
    }
next:     for(i=0;i<=j;i++)         //将转换为二进制的数组复制到全局变量指数数组中 
              e[i]=m[i];
          return j;
} 
 
//大数减法运算
void BigSubtract(int x[],int y[],int len1,int len2){
	int i;
	for(i=0;i<len1;i++)
    {
		if(x[i]<y[i])
		{
			x[i]=x[i]+10-y[i];
			x[i+1]--;
		}
		else
		    x[i]=x[i]-y[i];
	}
	for(i=len1;x>=0;i--)
	{
		if(x[i])
		{
			digit=i+1;
			break;
		}
	}
}

//大数除法运算 
int BigDivision(int a[],int b[],int len1,int len2){
	  int i,j=0,k=0,t,temp,len;
	  int z[len1];
	  int m[1024];
	  for(i=0;i<1024;i++)
	     m[i]=b[i];
	   	    
	if(len1<len2)        //当被除数位数 小于 除数位数时 
		{
			return len1;
		}
		else           //当被除数位数 大于或者 除数位数时
		{
		    len=len1-len2;             //两个大数位数的差值
		    for(i=len1-1;i>=0;i--) //将除数后补零,使得两个大数位数相同。
			 {
				if(i>=len)
					b[i]=b[i-len];
				else
					b[i]=0;
			 }
			 len2=len1;                 //将两个大数数位相同 		
		   	 digit=len1;	            //将原被除数位数赋值给digit 
			 for(j=0;j<=len;j++)
              {
				z[len-j]=0;
				while(((temp=judge(a,b,len1,len2))>=0)&&digit>=k)//判断两个数之间的关系以及位数与除数原位数的关系 
				{	
					BigSubtract(a,b,len1,len2);	      //大数减法函数			    
					z[len-j]++;             //储存商的每一位
					len1=digit;                  //重新修改被除数的长度
					if(len1<len2&&b[len2-1]==0)		
						len2=len1;          //将len1长度赋给len2;						
				}
				if(temp<0) 
				{
					for(i=1;i<len2;i++)
						b[i-1]=b[i];
					b[i-1]=0;
					if(len1<len2) 
						len2--;			        				        
				}
			  }
			  
		   for(i=len1;i>0;i--)
			{
				if(a[i])
					break;
			}
			int z=i+1;
		   for(i=0;i<1024;i++)        //计算出b的数位大小 
	         b[i]=m[i];   
           return z;
		} 
	} 

//大数除法运算的辅助函数 
int judge(int x[],int y[],int len1,int len2)
{
	int i;
	if(len1<len2)
		return -1;
	if(len1==len2)                       //若两个数位数相等 
	{
		for(i=len1-1;i>=0;i--)
		{
			if(x[i]==y[i])                 //对应位的数相等 
				continue;
			if(x[i]>y[i])            //被除数 大于 除数,返回值为1 
				return 1;
			if(x[i]<y[i])            //被除数 小于 除数,返回值为-1 
				return -1;
		}
return 0;                    //被除数 等于 除数,返回值为0 
	}	
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值