大数的四则运算

参考:加减乘除

手动模拟小学生列竖式

 

一、大数加法(都是正数时)

用两个数组分别逆序存储输入的数,每个位都分别相加,判断是否进位

代码:

#include<stdio.h>//大数加法 
#include<string.h>
#include<math.h>
#include<algorithm> 
using namespace std;
const int maxn = 1e4+7;
#define Max(a,b) a>b?a:b
char str1[maxn],str2[maxn];
int a[maxn],b[maxn];
void strv(char str[],int a[],int n)//用数组逆序存储 
{
	for(int i=0,j=n-1;i<n;i++,j--)
	{
		a[j]=str[i]-'0';
	}
}
int main()
{
		while(~scanf("%s%s",str1,str2))
		{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		int n1=strlen(str1);
		int n2=strlen(str2);
		strv(str1,a,n1);
	    strv(str2,b,n2);
		int i,w;
		int k=Max(n1,n2);
		for(i=0,w=0;i<k;i++){
			a[i]=a[i]+b[i]+w;
			w=a[i]/10;
			a[i]%=10;
		}
			if(w) 
			a[k]+=w;
		for(int i=k;i>=0;i--)//相加后的和,可能比最大的数还要多一位 
		{
			if(i==k&&a[k]==0)
			 continue;
			printf("%d",a[i]);
		}
		printf("\n");
	}
	return 0;
}

 

大数加法(可能为负数时)

参考:博客链接

方法:

第一步:将字符串转化为数组存储,若为负数,就把所有位的数都变成负的存进数组(不要符号位) 

第二步:对应位相加,并把结果保存在c数组里,注意进位

第三步:判断最高位正负,最高位为正,则最终结果一定为正;

最高位为负,最终答案一定为负,这时,提出来一个负号,也就是先输出一个负号,然后c[i] = -c[i]

第四步:从个位开始,小于0的向前借一位

代码51nod 1005大数加法链接

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
const int maxn=1e4+7;
char s1[maxn],s2[maxn];
int a[maxn],b[maxn],c[maxn];
int deal(char str[],int a[])//第1步 对输入的数进行处理 
{
	int n=strlen(str);
    if(str[0]=='-')//若为负数,就把所有位的数都变成负的存进数组(不要符号位) 
    {
    	for(int i=0;i<n-1;i++)
    	{
    		a[i]=str[i+1]-'0';
    		a[i]=-a[i];
		}
		n--;
	}
	else
	{
		for(int i=0;i<n;i++)
		{
				a[i]=str[i]-'0';
		}
	}
	return n;
}
int main()
{
	while(~scanf("%s%s",s1,s2))
	{
		int len1=deal(s1,a);
		int len2=deal(s2,b);
		int up=0,k=0,i,j;
		///从后向前对应位相加,把个位保存在c数组的第一位
		for(i=len1-1,j=len2-1;i>=0&&j>=0;i--,j--)//第2步 
		{//先处理相同位数部分
			c[k]=(a[i]+b[j]+up)%10;
			up=(a[i]+b[j]+up)/10;
			k++;
		}
		 //处理多出来的位数
		if(len1>len2)
		{
			while(i>=0)
        {
            c[k]=(a[i]+up)%10;
            up=(a[i]+up)/10;
            k++;
            i--;
        }
		}
		if(len1<len2)
		{
			while (j >= 0)
        {
            c[k]=(b[j]+up)%10;
              up=(b[j]+up)/10;
            k++;
            j--;
        }
		}
		//下面5行是(都为正数时)相加后比输入时(最大的位数)多一位的情况
		if(up!=0)
		{
			c[k]=up;   
			k++;
		}
		//*** 
		
		if(c[k-1]<0)//第3步 
		{//判断最高位的正负 ,最高位为负,最终答案一定为负 
			for(int i=0;i<k;i++)
			c[i]=-c[i];
			printf("-");
		}
		for(int i=0;i<k;i++)//第4步 
		{//从个位开始,小于0的向前借一位
		   if(c[i]<0)
		   {
		   	c[i]+=10;
			c[i+1]--;
		   }
		}
		if(k==1&&c[0]==0)
		printf("0\n");
		else
	{
	  while(!c[k-1])//前导清0 
	  k--;	
	 for(int i=k-1;i>=0;i--)
	 printf("%d",c[i]);
	 printf("\n");
	}
	}
    return 0;
}

 

二、大数减法

主要是使前一个数比后一个数大,且逆序后,让小的那个数后面补0保证两个数位数相同,最后在相减(别忘了去除前导0

代码:

#include<stdio.h>//大数减法 
#include<string.h>
#include<math.h>
#include<algorithm> 
#define Max(a,b) a>b?a:b
using namespace std;
const int maxn=1e3+7;
char aa[maxn],bb[maxn],aacopy[maxn],bbcopy[maxn];
int a[maxn],b[maxn];
int main()
{
	while(~scanf("%s%s",aa,bb))
	{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		int flag=1;//正负号 
		int len1=strlen(aa);
		int len2=strlen(bb);	
		
		for(int i=0;i<len1;i++)
		aacopy[i]=aa[i];
		for(int i=0;i<len2;i++)
		bbcopy[i]=bb[i];
		
		//将字符串转化为整数存入数组 且总是第一个数大于第二个数 
		//b存小的数,a存大的数 
		if(len1<len2)
		{
			for(int i=0;i<len1;i++)
			b[i]=aacopy[len1-i-1]-'0';
			for(int i=len1;i<len2;i++)//中间差的位数用0补上 
			b[i]=0;
			for(int i=0;i<len2;i++)
			a[i]=bbcopy[len2-i-1]-'0';
			flag=0;
			
		}
		
		else if(len1>len2)
		{
			for(int i=0;i<len1;i++)//用数组逆序存储 
			a[i]=aacopy[len1-i-1]-'0';
			for(int i=0;i<len2;i++)
			b[i]=bbcopy[len2-i-1]-'0';
			for(int i=len2;i<len1;i++)
			b[i]=0;	
		}
		
		else if(len1==len2)
		{
			if(aa>=bb)
			{
				for(int i=0;i<len1;i++)
				a[i]=aacopy[len1-i-1]-'0';
				for(int i=0;i<len2;i++)
				b[i]=bbcopy[len2-i-1]-'0';
			}
			
			else
			{
				for(int i=0;i<len1;i++)
				a[i]=bbcopy[len1-i-1]-'0';
				for(int i=0;i<len2;i++)
				b[i]=aacopy[len2-i-1]-'0';
				flag=0;
			}
		}
		
		int len=Max(len1,len2);
		if(flag==0)
		printf("-");
		//大数相减 
		int c[maxn];
		for(int i=0;i<len;i++)
		{
			c[i]=a[i]-b[i];
			if(c[i]<0)
			{
			c[i]=c[i]+10;	
			a[i+1]=a[i+1]-1;
			}
		}
		//去除前导0 
		while(c[len-1]==0&&len!=1)
		{
			len--;
    	}
		for(int i=len-1;i>=0;i--)
		printf("%d",c[i]);
        printf("\n");
	}	
return 0;
}

 

三、大数乘法

(这里写的大数乘法和除法只适用于输入数长度不是特别大时,如:链接:大数乘法v2  大数除法v2

A,B的长度 <= 100000,A,B >= 0 此时用此方法会超时,特别大的具体算法,之后再更新。)

规律: 即一个数的第i 位和另一个数的第j 位相乘所得的数,一定是要累加到结果的第i+j 位上。这里i, j 都是从右往左,从0 开始数。
    ans[i+j] = a[i]*b[j];

      7 8 9 6 5 2
×         3 2 1 1
-----------------
      7 8 9 6 5 2   <---- 第1趟 
    7 8 9 6 5 2     <---- 第2趟 
   ..........       <---- 第n趟 
-----------------
  ? ? ? ? ? ? ? ?   <---- 最后的值用另一个数组表示 

例题:1027 大数乘法

代码:

#include<stdio.h>//大数乘法 
#include<string.h>
#include<math.h>
#include<algorithm> 
using namespace std;
const int N=1e3+7;
char str1[N],str2[N];
int a[N],b[N],c[2*N];
void strv(char str[],int a[],int n)//用数组逆序存储 
{
	for(int i=0,j=n-1;i<n;i++,j--)
	{
		a[j]=str[i]-'0';
	}
}
int main()
{
	while(~scanf("%s%s",str1,str2))
	{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(c,0,sizeof(c));
		if(str1[0]=='0'||str2[0]=='0')
		printf("0\n");
		else
		{
			int n1=strlen(str1);
			int n2=strlen(str2);
			strv(str1,a,n1);
	        strv(str2,b,n2);
			//模拟每一位的竖式计算过程(从个位开始) 
			for(int i=0;i<n1;i++)
			{
				for(int j=0;j<n2;j++)
				{
				 c[i+j]=a[i]*b[j]+c[i+j];//按位进行乘法
                 c[i+j+1]=c[i+j+1]+c[i+j]/10;//进位
                 c[i+j]=c[i+j]%10;
				}
			}
			int n=n1+n2;
			while(!c[n])//前导清0 
			n--;
			for(int i=n;i>=0;i--)
			printf("%d",c[i]);
			printf("\n");
		}
	}
	return 0;
}

 

四、大数除法

我看人家的代码写的特别详细,就直接粘别人的代码了,原博客链接在最上面。

#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;
}

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值