一、高精度运算
什么是高精度运算?我们都知道,数据类型是有大小范围的。
- 整型数据 int 能表示的数的范围为:-2147483648至2147483647(-2^31至2^31-1)
- 长整型数据 long long 能表示的数的范围为:-9223372036854775808~9223372036854775807(-2^63至2^63-1)。
那么当所要求解的数的大小还要再大时,就不能使用上述的方式存储数据进行运算。此时我们可以使用高精度运算进行解决。
二、高精度加法
高精度加法,实际上就是我们从加法的定义出发,利用数组表示每一位,通过“竖式运算”的方式进行进位相加,最终得出答案。为了保证数字的连贯,我们可以使用字符串或字符数组来表示,之后再利用相应的ASCII码值进行转换即可。
- 先定义两个字符串
string a,b; //使用字符数组,则是已知数据的长度,若不清楚可采用字符串
cin>>a>>b; //注意这个时候我们输入的数字就用字符串来表示了
想想我们列竖式计算加法时的思想是怎样的:将两个数字对应的个,十,百...位都对齐进行相对应的加法计算,满10就进1,不满则不进。从个位开始对齐,如果因为两个数字 的位数不同而导致其中一个数字的高位没有对应的数字对齐,那么我们就要在另一个数字对应的位置上进行空位补0。因此,我们需要先得到两个字符串中较长的字符串长度作为边界条件,然后进行补0操作:
既然我们已经用字符数组的形式将数字表示了出来,那我们就可以利用取对应下标的方法将对应的数字进行相加。但我们要注意一个问题:我们通常的列竖式加法运算是从末尾开始逐次相加,对应到我们的字符数组中,我们就要得到两个字符数组中较长的作为边界条件,来写这个for循环。
- 判断两个数的长度,将较短的数放置到字符串 a 中,然后进行高位补 0
if(a.size()>b.size() swap(a,b);
int aa=a.size(),bb=b.size(); //注意需要提前用变量记录两个字符串的长度,不可以在for循环中直接使用size()函数
for(int i=1;i<=b.size()-a.size();i++)
a='0'+a;
- 补0操作使得每一位数字都能够对齐后,我们就可以开始进行加法的操作:
for(int i=a.size()-1;i>=0;i--)
a[i]=(a[i]-48)+(b[i]-48); //将字符转成数字后参与运算,然后存储到a[i]中,注意此时存储在字符串里的是答案数字
- 处理进位问题
两个数相加后有可能超出10,此时我们需要向前进位。因此接下来我们要进行进位的判断与操作。特别需要注意的是,如果最高位也需要再进一位时,我们在最后输出之前需要添加进位后的数字“1”在答案字符串之前。
for(int i=a.size()-1;i>=1;i--)
{
if(a[i]>=10)
{
a[i-1] += a[i]/10; //先进位
a[i]% = 10; //进位后剩余的数字
}
}
如果最高位需要进位,那么先将进位的答案求出,然后处理a[0]的答案,最后将进位的答案放在最前面连接
if(a[0]>=10)
{
char t=a[0]/10;
a[0]%=10;
a=t+a;
}
- 输出
实现一切之后,我们就可以输出。注意:此时存在字符串里的是答案数字,但由于ASCII码的影响,直接输出会答案错误,因此我们需要将其转换为字符形式才能够正确显示。
for(int i=0;i<a.size();i++)
cout<<char(a[i]+'0');
三、高精度减法
高精度减法和高精度加法的原理一样,都是利用“竖式运算”的原理进行处理。
- 判断两个谁谁大谁小
如果大数减小数,得到的是正数;如果小的数减大数,相当于调换位置相减,但结果为负。
string a,b;
int f=0; // f为0表示是大数减小数,结果为正
cin>>a>>b;
if(a.size()<b.size()||a.size()==b.size()&&a<b)
{
swap(a,b);
f=1;
} //将较小的数放到字符串b,但此时要注意swap函数改变了原本被除数与除数的关系,原本是小数减大数答案是负数,现在则变成了大数减小数,所以我们需要新建一个变量来做标记答案是一个负数。如果此时两个字符串的长度一致,则可以比较它们的长度来判断将较小的数放到字符串b
- 高位补 0
int aa=a.size(),bb=b.size();
for(int i=1;i<=a.size()-b.size();i++)
{
b='0'+b; //高位补0
}
- 竖式计算,对齐相减
for(int i=a.size()-1;i>=0;i--)
{
a[i]=(a[i]-’0’)-(b[i]-’0’); //相减,将答案数字存进字符串a中
}
- 处理借位问题
for(int i=a.size()-1;i>=0;i--)
{
if(a[i]<0)
{
a[i-1]-=1; //如果是负数,说明不够减,需要向前一位借1
a[i]=a[i]+10;
}
}
- 删除前导0
int t=0; //但减法还需要有一个额外的判断就是前导0是不需要输出的
if(f==1) cout<<”-”; //f为1说明之前是小数减大数,所以要先输出“-”号
for(int i=0;i<a.size();i++)
{
if(a[i]==0)
{
if(t==1) cout<<char(a[i]+'0'); //t==1时说明这不是前导0
}
else
{
cout<<char(a[i]+'0');
t=1; //前导0全部输出完,t标记为1
}
}
标签:10,数字,int,L01,C08,加法,字符串,减法,size
From: https://blog.csdn.net/ch_yang123/article/details/139534701