大数运算(5)——大数除法(取模、取余)

有关于大数除法的运算可以大致分为两种:一种是求商,另一种是求余数(取余)。

有两个大整数a和b,当a==b时,a/b==1,余数是0。(a!=0,b!=0)

                                     当a>b时,a/b>=1,余数需要通过计算求得。

                                     当a<b时,a/b=0,余数就是a。

而我们经常需要求的便是当a>b,这种情况我们该如何求商和余数呢?

其实基本的思想就是反复做减法,看看从被除数里最多能减去多少个除数,商就是多少。一个一个减显然太慢,如何减得更快一些呢?

以28536 除以23 为例来看一下:开始商为0。

先减去23 的1000 倍,就是23000,发现够减1 次,余下5536,于是商的值就增加1000;

然后用5536减去2300,发现够减2 次,余下936,于是商的值增加200,即1200;

再用936 减去230,够减4 次,余下16,于是商值增加40,即1240。

最后,发现余下的数比23小,即为余数,即28536 / 23 得1240余16。

这时,你会发现这其实就是咱们人工计算时相当于列的竖式。

另外,注意:我这里写的是有关大数除以大数的除法,同样适用于大数除以int类型范围的数,当然,也可以另写关于大数除以int的数。

这里写的全部是大整数,不包括小数。

下面是C语言代码实现:

#include<stdio.h>
#include<string.h>
char a[100],b[100];//用两个字符串用来输入两个大数 
int x[100],y[100],z[100],m[100];//被除数  除数  商  余数 
int digit;//大数的位数 
void sub(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-1;i>=0;i--)//判断减法结束之后,被除数的位数 
	{
		if(x[i])
		{ 
			digit=i+1;
			break;		   
		} 
	}
}
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 
	}	
}
int main()
{
	int i,j=0,k=0,temp;
	int len1,len2,len;//len两个大数位数的差值   
	while(~scanf("%s %s",a,b))
	{
		len1=strlen(a);//被除数位数
		len2=strlen(b);//除数位数
		for(i=len1-1,j=0;i>=0;i--)//将字符串中各个元素倒序储存在数组中 
			x[j++]=a[i]-'0';
		for(i=len2-1,k=0;i>=0;i--)
			y[k++]=b[i]-'0';		    
		if(len1<len2)//当被除数位数 小于 除数位数时 
		{
			printf("商是:0\n");
			printf("余数是:");
			puts(a); 
		}
		else //当被除数位数 大于或者 除数位数时
		{
			len=len1-len2;//两个大数位数的差值
			for(i=len1-1;i>=0;i--)//将除数后补零,使得两个大数位数相同。被除数:4541543329 除数:98745,加零后:9874500000 
			{
				if(i>=len)
					y[i]=y[i-len];
				else
					y[i]=0;
			}
			len2=len1;//将两个大数数位相同 		
			digit=len1;	//将原被除数位数赋值给digit 
			for(j=0;j<=len;j++)
            {
				z[len-j]=0;
				while(((temp=judge(x,y,len1,len2))>=0)&&digit>=k)//判断两个数之间的关系以及位数与除数原位数的关系 
				{	
					sub(x,y,len1,len2);	//大数减法函数			    
					z[len-j]++;//储存商的每一位
					len1=digit;//重新修改被除数的长度
					if(len1<len2&&y[len2-1]==0)		
						len2=len1;//将len1长度赋给len2;						
				}
				if(temp<0)//若被除数 小于 除数,除数减小一位。例如:被除数:4541543329 除数:(原)98745,(加零后)9874500000,后退一位后:0987450000 
				{
					for(i=1;i<len2;i++)
						y[i-1]=y[i];
					y[i-1]=0;
					if(len1<len2) 
						len2--;			        				        
				}
			}
			printf("商是:");
			for(i=len;i>0;i--)//去掉前缀0 
			{
				if(z[i])
					break;
			}
			for(;i>=0;i--)
				printf("%d",z[i]);
			printf("\n");
			printf("余数是:");
			for(i=len1;i>0;i--)
			{
				if(x[i])
					break;
			}
			for(;i>=0;i--)
				printf("%d",x[i]);
			printf("\n");
		}
	}
	return 0;
}



  • 24
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值