模拟:超大整数加减法

无数次面对这样的问题,两个长度是几千甚至上万的字符串相加或相减,输出结果。这次专门练习写一遍。

校赛ACM时候就卡在这种题上了,不然就能AC七道题了!!

        1.两个大数相加的函数比相减的简单些,不用考虑结果会不会是负数的问题。接收到两个字符串和一个要存储和的目标字符串,先反转两个字符串,后以较长字符串为目标,挨个加到存储和的字符串。当当前长度小于短串的时候,每一位再加上短串的对应位,当前位相加后超过9则进位。长度超出短串后,加上长串对应位的同时也要判断当前位有没有超过9。结束后注意判断一下和有没有超出长串的长度(可能会进位),用字符串结束标志'\0'结束目标字符串即可,反转目标字符串后结束函数。

void BigNumAdd(char* a, char* b, char* str)
{
	if (strlen(a)<strlen(b))
	{
		BigNumAdd(b, a, str);
		return;
	}
	reverse(a), reverse(b);
	for (int i = 0; i <= strlen(a); i++)
		str[i] = '0';
	for (int i = 0; i<strlen(a); i++)
	{
		str[i] += a[i] - '0';
		if (i<strlen(b))
		{
			int num = str[i] - '0' + b[i] - '0';
			if (num>9)
			{
				str[i] = num - 10 + '0';
				str[i + 1]++;
			}
			else
			{
				str[i] = num + '0';
			}
		}
		else
		{
			if (str[i]>'9')
			{
				str[i] -= 10;
				str[i + 1]++;
			}
		}
	}
	if (str[strlen(a)] > '0')
		str[strlen(a) + 1] = 0;
	else
		str[strlen(a)] = 0;
	reverse(str);
}

a和b是相加的两个字符串,str是目标字符串(存储和)

void reverse(char* str)
{
	int ind = strlen(str) - 1;
	int ins = 0;
	while (ins<ind)
	{
		char ch = str[ind];
		str[ind] = str[ins];
		str[ins] = ch;
		ind--, ins++;
	}
	return;
}

这是用到的反转字符串函数,头尾开始交换,直到中间碰头结束。

        2.两个大数相减先考虑的是两数大小问题,只有大数减小数才不会出现负数的情况。我先判断两字符串长度,如果两字符串长度相同再逐位判断大小,长度不满足被减数大于减数则交换被减数和减数,并用返回值来表示此次减法运算是否结果为负。减数和被减数相同则直接赋值目标字符串0,并结束函数。

        满足被减数大于减数后,反转两字符串。和大数相加的思路相同,从低位开始逐位判断相减后有没有小于0,如果小于则将高位减一。没有减数后也要逐位判断有没有出现小于0的数。最后要注意的是,高位可能若干位因为被减或借位成0,所以遍历找到第一个不为0的高位。将上一位赋值'\0'结束字符串,反转后完成大数相减。

int BigNumSub(char*a, char* b, char* str)
{
	int i = 0;
	int j = 0;
	while (1)
	{
		if (strlen(a)<strlen(b))
		{
			BigNumSub(b, a, str);
			return 1;
		}
		if (strlen(a)>strlen(b))
			break;
		else
		{
			if (a[i]<b[j])
			{
				BigNumSub(b, a, str);
				return 1;
			}
			if (a[i]>b[j])
				break;
			else
			{
				if (i == strlen(a))
				{
					str[0] = '0';
					str[1] = 0;
					return 0;
				}
				i++, j++;
			}
		}
	}
	reverse(a), reverse(b);
	for (int i = 0; i <= strlen(a); i++)
		str[i] = '0';
	for (int i = 0; i<strlen(a); i++)
	{
		str[i] += a[i] - '0';
		if (i<strlen(b))
		{
			int num = str[i] - b[i];
			if (num<0)
			{
				str[i] = num + 10 + '0';
				str[i + 1]--;
			}
			else
			{
				str[i] = num + '0';
			}
		}
		else
		{
			if (str[i]<'0')
			{
				str[i] = '9';
				str[i + 1]--;
			}
		}
	}
	int st = strlen(a) - 1;
	while (str[st] == '0')
		st--;
	str[st + 1] = 0;
	reverse(str);
	return 0;
}

a是被减数字符串,b是减数字符串,str是目标字符串。返回值非0表示结果为负数,为0则为正数或0。

所用到的反转字符串函数同上。


之后再写大数乘法、除法、开方?

#include<stdio h> #include<string h> int main { int len1 len2 i j k t m; char str1[100] str2[100] str[100]; while scanf "%s %s" str1 str2 EOF { m 0; len1 strlen str1 ; len2 strlen str2 ; for i 0;i<len1;i++ str1[i] 48; for j 0;j<len2;j++ str2[j] 48; if len1 len2 {for i 0;i<len1;i++ { if str1[i]>str2[i] {for i len1 1 j len2 1 k 0;j> 1;i j k++ { if str1[i]<str2[j] {str1[i]+ 10;if str1[i 1]>0 str1[i 1] ;else {str1[i 1] 9;str1[i 2] ;}} str[k] str1[i] str2[j]; } break; } if str2[i]>str1[i] { for i len1 1 j len2 1 k 0;j> 1;i j k++ { if str1[i]>str2[j] {str2[j]+ 10;if str2[j 1]>0 str2[j 1] ;else {str2[j 1] 9;str2[j 2] ;}} str[k] str2[j] str1[i]; } printf " " ; break; } else{for i 0;i<len1;i++ str[i] 0;break;} } t len1 1; } if len1>len2 { for i len1 1 j len2 1 k 0;j> 1;i j k++ { if str1[i]<str2[j] {str1[i]+ 10;if str1[i 1]>0 str1[i 1] ;else {str1[i 1] 9;str1[i 2] ;}} str[k] str1[i] str2[j]; } for i len1 len2 1 k len2;k<len1;i k++ { str[k] str1[i]; } t len1 1; } if len1<len2 { for i len1 1 j len2 1 k 0;j> 1;i j k++ { if str1[i]>str2[j] {str2[j]+ 10;if str2[j 1]>0 str2[j 1] ;else {str2[j 1] 9;str2[j 2] ;}} str[k] str2[j] str1[i]; } for j len2 len1 1 k len1;k<len2;j k++ { str[k] str2[j]; } printf " " ; t len2 1; } for i t;i> 1;i { if m 0 printf "%d" str[i] ; if m 0&&str[i] 0 {printf "%d" str[i] ;m++;} } if m 0 printf "0" ; printf " n" ; } return 0; }">#include<stdio h> #include<string h> int main { int len1 len2 i j k t m; char str1[100] str2[100] str[100]; while scanf "%s %s" str1 str2 EOF { m 0; len1 strlen str1 ; len2 strlen str2 ; for i 0;i<len1;i++ str1[i] 48; for j 0;j<len2;j++ str2[j] 48; if len1 len2 [更多]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值