如何用C语言实现超大整数(不大于101000)的加减运算
由于C语言的整型数据储存机制,要想用C语言实现超大整数的加减运算可不像下面这么简单
int main()
{
long long int a,b;
scanf("%d %d",&a,&b);
printf("%d\n",a+b);
}
如果使用上面的代码进行运算,数据稍大就可能发生溢出的现象,导致最终的结果不正确,并且有时难以察觉。那么该如何利用C语言实现超大整数的加减运算呢?
在我们人类眼中,字符串和数字是完全一样的,如果给定一串数字:12345,我们既可以认为它是一个数字(一万二千三百四十五),也可以认为它是一段数字序列(一二三四五)。基于此,我们便可以用字符串来储存超大整数,并将加减运算规则应用在字符串上。
加法规则:个位对齐,满十进一
减法规则:个位对齐,不够借位
首先我们需要获取用户给定的两个字符串记为num1和num2。由于正数前面是没有’+‘的,而负数前面是有’-'的,因此我们需要规范num1和num2的形式,确保num1[0]和num2[0]中保存的都是自身符号,这样可以让我们后面的实现过程更加顺利。
具体实现方法是:
获取需要规范形式的字符串,记为num
如果num[0]!='-'
{
num中所有元素后移一个单位
num[0]='+'
}
完成对字符串形式的规范后,我们需要实现个位对齐。考虑到两个字符串的长度可能不同,我选择的方法是将num1和num2的数字顺序颠倒(不改变符号的位置),如:
+123456 -> +654321
-134 -> -431
这样颠倒顺序后的num1和num2的个位都处在了索引为1的位置,我们只需在完成运算之后把最终结果再颠倒过来即可。
做好了这些准备工作后,就可以编写运算时的代码了。
首先,我们需要通过数字的符号确定运算的类型以及最终结果的符号。
符号相同:绝对值相加,符号取决于数字的符号
符号不同:较大绝对值-较小绝对值,符号取决于绝对值较大数的符号
至此,最终结果的符号我们已经确定下来了,我们还需要实现绝对值之间的加减运算。
这部分实现方法使用代码表示更为简洁,因此给出具体代码
各个变量的含义如下:
ans:用于保存最终答案的字符串(a[0]保存了符号)
num1:长度更长的字符串
num2:长度更短的字符串
len1:num1的长度
len2:num2的长度
//绝对值相加
for (i=1; i<len2; i++) //先遍历更短的字符串
{
ans[i]+=num1[i]+num2[i]-'0';
//此时ans[i]中保存的就是字符形式的数字
if (ans[i]>=10+'0') //进位
{
ans[i]-=10;
ans[i+1]++;
}
}
for (i=len2; i<len1; i++) //再遍历更长的字符串
{
ans[i]+=num1[i];
if (ans[i]>=10+'0') //进位
{
ans[i]-=10;
ans[i+1]++;
}
}
len=strlen(ans); //取此时ans的长度,以便确定'\0'的最终位置
ans[len]='\0';
for (i=len-1; ans[i]<'0'; i--)
//考虑到进位时可能出现ans[i]+'0'='对应数字'的情况,对此进行检查
{
ans[i]+='0';
}
备注:
1.声明了ans后务必进行初始化,将其中的元素全部置零:
memset(ans,0,ans的长度)
2.要分两次遍历字符串的原因:
由于没有对num2[i](i>len2)进行初始化,num2[i](i>len2)可
能是一些乱七八糟的值,如果此时进行运算,得到的ans[i]也会是一些
乱七八糟的值。若希望仅用一次for循环,则应该在读取字符串前使用
memset(num2,'0',num2的长度)
进行初始化。
得到最终的ans后,根据其符号进行输出即可。
绝对值相减的方法与此大同小异,因此不再赘述。