高精度减法

前言

有些时候我们需要计算两个很大的整数的差,但是 C++ 中 int或者long long 类型的范围很小,无法存储大整数。

下段代码两个大整数输入转化为整型数组,并用数组计算出两数的差,并将结果输出。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
#include<cstring>
using namespace std;
void rev(int fir[],int sec[],string a,string b) //将两个字符串转化为数组
{
for(int i=0;i<a.length();i++) //倒序存入fir数组中
{
fir[i]=a[a.length()-i-1]-'0';
}
for(int i=0;i<b.length();i++) //倒序存入sec数组中
{
sec[i]=b[b.length()-i-1]-'0';
}
}
bool max(int a,int b) //返回较大值
{
return a>b?a:b;
}
int main()
{
string a,b; //定义两个字符串
int fir[20002],sec[20002],ans[20002],i,x,len; //定义需要用到的三个数组
while (cin>>a>>b) //循环读入两个大整数
{
if (a.length() < b.length() || (a.length() == b.length() && a < b)) //将被减数始终保持大于等于减数
{
swap(a, b); //交换被减数和减数的顺序
cout<<'-'; //输出负号
}
len=max(a.length(),b.length()); //计算两个数中最长数字的位数
for(i=0;i<=len;i++) //将两个数组清零
{
fir[i]=0;
sec[i]=0;
ans[i]=0;
}
rev(fir,sec,a,b); //调用rev函数,将两个字符串倒序存入数组中
for(i=0;i<=len;i++) //从最低位开始计算
{
if(fir[i]<sec[i]) //如果该位被减数小于减数,则要借位
{
fir[i]+=10;
fir[i+1]-=1;
}
ans[i]=fir[i]-sec[i]; //计算差并存入ans数组
}
while (ans[len]==0&&len!=0) //去掉计算结果最高位的多余0
{
len--;
}

for(int i=len;i>=0;i--) //反序输出答案
{
cout<<ans[i];
}
cout<<endl;
}
}

这种竖式计算的方式,也正是在模拟我们小学时学到的手算减法的过程。

rev函数作用

rev 函数将输入的两个字符串逆序存入数组中,主要是为了方便从最低位开始做减法计算,从而保证了每位相减时的对应关系。

举个例子,假设输入的两个字符串分别为 123456 和 67,我们需要先将它们转化为整型数组。如果不逆序存储,那么数组存储方式就是:

输入:

fir: 1 2 3 4 5 6

sec: 6 7

实际存储:

fir: 1 2 3 4 5 6 0 0 0 0 … //后面还有很多 0
sec: 6 7 0 0 0 0 0 0 0 … //后面还有很多 0

注意:这里用 0 表示初始化时的默认值。

如果没有rev函数,相减时就不方便了(无法做到个位对齐个位、十位对其十位…)。采用倒序存储方式,可以方便地从低位向高位计算从而达到简化计算的目的。