C语言大数相加实现方法分析

使用C语言内置的int,在32位系统下最大只能表示2^31-1,也就是2147483647,想要表示更大的数可以使用字符串。

下面是楼主实现字符串数字相加的分析过程:

1.首先来个简单的,单个数字字符相加求和

inline int addchar(char c1,char c2,char &s){
	int t=c1+c2;
	//0-9的ascii码是48-57
	if(t<106){//5的ascii码是53,小于106说明相加不超过10
		s=(char)(t-48);//返回对应数字的char
		return 0;
	}else{
		s=(char)(t-58);//再多减去10
		return 1;
	}
}

这个函数肯定会经常被调用,所以加上inline,最后一个参数保存相加结果的最后一位,如果有进位返回1,否则返回0。

测试一下发现没有问题,我们继续分析。

最基础的1位加法功能写好了,接下来就只要按照外面小学时学的加法计算方法把每一位一个个相加即可。

2.先写个简单的情况:假设计算过程中没有进位并且2个求和的字符串长度相等,比如1122+2233,结果应该是3355

函数定义

void bignumadd(const char* num1,const char* num2,char* sum){//大数相加
}

第一步先要获取输入字符串的长度,然后开始遍历,当然要从最后一位往前遍历一个个相加,保存结果的时候,由于不知道最后结果到底有多少,所以我们可以倒着放(第一位放个位相加结果,第二位放十位相加结果...),最后逆向输出一下即可

比如最后结果等于3355,那么sum={'5','5','3','3',0,0,0,0}

所以函数是这样的

void bignumadd(const char* num1,const char* num2,char* sum){//大数相加
	size_t len1=strlen(num1);//得到输入字符串长度,这里假设2个数字是一样长的
	for(size_t i=0;i<len1;++i){//遍历每个字符
		//注意计算的时候从最后一位开始,保存的时候从第一位开始
		addchar(num1[len1-i-1],num2[len1-i-1],sum[i]);
	}
}

输出结果的函数

void showsum(const char* s){//显示计算结果
	size_t len=strlen(s);
	for(int i=len-1;i>-1;--i){//从最后一位开始逆序输出
		putchar(s[i]);
	}
}

接着我们在主函数里面测试一下

int main() {
	const char* num1="1122";
	const char* num2="2233";
	char s[100]={0};//分配100字节的栈空间存放结果
	printf("%s+%s\n=",num1,num2);
	bignumadd(num1,num2,s);
	showsum(s);
	getchar();
	return 0;
}

看到输出为

1122+2233

=3355

验证通过

3.然后再来个稍微复杂点的,还是不进位,但是2个数的长度不一定相同

当遍历完短的字符串之后,长的字符串高位剩下部分每一位直接和0相加即可,代码如下

void bignumadd(const char* num1,const char* num2,char* sum){//大数相加
	size_t len1=strlen(num1),len2=strlen(num2),i=0;//得到输入字符串长度
	if(len1>len2){//如果第一个字符串长
		for(;i<len2;++i){//len2比较小,先遍历完
			addchar(num1[len1-i-1],num2[len2-i-1],sum[i]);
		}
		for(;i<len1;++i){//剩下部分
			addchar(num1[len1-i-1],'0',sum[i]);//第一个字符串多出来的直接和0加
		}
	}else{//如果第二个字符串长
		for(;i<len1;++i){//len1比较小,先遍历完
			addchar(num1[len1-i-1],num2[len2-i-1],sum[i]);
		}
		for(;i<len2;++i){//剩下部分
			addchar('0',num2[len2-i-1],sum[i]);//第二个字符串多出来的直接和0加
		}
	}
}

然后在主函数里面把num1改为111,结果是2344,再把num2改成5,结果是116,说明没问题

4.接下来我们就可以考虑带进位的了,按照加法的计算规则,进位要加到高位上去,因此用一个变量保存一下这位相加的时候有没有进位,下次再加上1就好了,为了方便,我们给最开始的1位加法做个小改动,给它添加一个参数

inline int addchar(char c1,char c2,int f,char &s){//带进位字符加法
	int t=c1+c2+f;
	//0-9的ascii码是48-57
	if(t<106){//5的ascii码是53,小于106说明相加不超过10
		s=(char)(t-48);//返回对应数字的char
		return 0;
	}else{
		s=(char)(t-58);//再多减去10
		return 1;
	}
}

f表示是否需要进位,最终的计算结果再加上f就行了

然后我们在计算的时候就可以很方便地处理进位了,代码如下

void bignumadd(const char* num1,const char* num2,char* sum){//大数相加
	size_t len1=strlen(num1),len2=strlen(num2),i=0;//得到输入字符串长度
	int f=0;//用于保存进位,第一次计算个位的时候进位肯定是0
	if(len1>len2){//如果第一个字符串长
		for(;i<len2;++i){//len2比较小,先遍历完
			f=addchar(num1[len1-i-1],num2[len2-i-1],f,sum[i]);
		}
		for(;i<len1;++i){//剩下部分
			f=addchar(num1[len1-i-1],'0',f,sum[i]);//第一个字符串多出来的直接和0加
		}
	}else{//如果第二个字符串长
		for(;i<len1;++i){//len1比较小,先遍历完
			f=addchar(num1[len1-i-1],num2[len2-i-1],f,sum[i]);
		}
		for(;i<len2;++i){//剩下部分
			f=addchar('0',num2[len2-i-1],f,sum[i]);//第二个字符串多出来的直接和0加
		}
	}
	//别忘记最高位还可能会进位
	for(;f>0;++i){
		f=addchar('0','0',f,sum[i]);
	}
}

重点就是addchar了,将上一次的进位结果也进行计算,同时保存本次进位结果

最后遍历完成的时候最高位还可能会有进位,别忘记处理了

然后我们在主函数中测试一下

num1=87,num2=9999,结果是10086,正确

是不是很简单O(∩_∩)O

下面是所有完整源代码

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

inline int addchar(char c1,char c2,int f,char &s){//1位加法,f表示进位
	int t=c1+c2+f;
	if(t<106){
		s=(char)(t-48);
		return 0;
	}else{
		s=(char)(t-58);
		return 1;
	}
}
void bignumadd(const char* num1,const char* num2,char* sum){//大数相加
	size_t len1=strlen(num1),len2=strlen(num2),i=0;//得到输入字符串长度
	int f=0;//用于保存进位
	if(len1>len2){//如果第一个字符串长
		for(;i<len2;++i){//len2比较小,先遍历完
			f=addchar(num1[len1-i-1],num2[len2-i-1],f,sum[i]);
		}
		for(;i<len1;++i){//剩下部分
			f=addchar(num1[len1-i-1],'0',f,sum[i]);//第一个字符串多出来的直接和0加
		}
	}else{//如果第二个字符串长
		for(;i<len1;++i){//len1比较小,先遍历完
			f=addchar(num1[len1-i-1],num2[len2-i-1],f,sum[i]);
		}
		for(;i<len2;++i){//剩下部分
			f=addchar('0',num2[len2-i-1],f,sum[i]);//第二个字符串多出来的直接和0加
		}
	}
	//别忘记最高位还可能会进位
	for(;f>0;++i){
		f=addchar('0','0',f,sum[i]);
	}
}
void showsum(const char* s){//显示计算结果
	size_t len=strlen(s);
	for(int i=len-1;i>-1;--i){//从最后一位开始逆序输出
		putchar(s[i]);
	}
}
int main() {
	const char* num1="87";
	const char* num2="9999";
	char s[100]={0};//分配100字节的栈空间存放结果
	printf(" %s+%s\n=",num1,num2);
	bignumadd(num1,num2,s);
	showsum(s);
	getchar();
	return 0;
}

这样就完成了大正整数的加法,减法和负数也是同样的思路,有兴趣的兄弟可以自己改改试试

楼主技术有限,要是有什么不好的地方欢迎指出哈

转载请注明出处https://blog.csdn.net/rtduq/article/details/79954816

阅读更多

没有更多推荐了,返回首页