高精度加法与减法.概述

一、高精度运算

什么是高精度运算?我们都知道,数据类型是有大小范围的。

  1. 整型数据 int 能表示的数的范围为:-2147483648至2147483647(-2^31至2^31-1)
  2. 长整型数据 long long 能表示的数的范围为:-9223372036854775808~9223372036854775807(-2^63至2^63-1)。

那么当所要求解的数的大小还要再大时,就不能使用上述的方式存储数据进行运算。此时我们可以使用高精度运算进行解决。

二、高精度加法

高精度加法,实际上就是我们从加法的定义出发,利用数组表示每一位,通过“竖式运算”的方式进行进位相加,最终得出答案。为了保证数字的连贯,我们可以使用字符串或字符数组来表示,之后再利用相应的ASCII码值进行转换即可。

  1. 先定义两个字符串
string a,b; //使用字符数组,则是已知数据的长度,若不清楚可采用字符串
cin>>a>>b; //注意这个时候我们输入的数字就用字符串来表示了

Copy

想想我们列竖式计算加法时的思想是怎样的:将两个数字对应的个,十,百...位都对齐进行相对应的加法计算,满10就进1,不满则不进。从个位开始对齐,如果因为两个数字 的位数不同而导致其中一个数字的高位没有对应的数字对齐,那么我们就要在另一个数字对应的位置上进行空位补0。因此,我们需要先得到两个字符串中较长的字符串长度作为边界条件,然后进行补0操作:

既然我们已经用字符数组的形式将数字表示了出来,那我们就可以利用取对应下标的方法将对应的数字进行相加。但我们要注意一个问题:我们通常的列竖式加法运算是从末尾开始逐次相加,对应到我们的字符数组中,我们就要得到两个字符数组中较长的作为边界条件,来写这个for循环。

  1. 判断两个数的长度,将较短的数放置到字符串 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;

Copy

  1. 补0操作使得每一位数字都能够对齐后,我们就可以开始进行加法的操作:
for(int i=a.size()-1;i>=0;i--)
	a[i]=(a[i]-48)+(b[i]-48); //将字符转成数字后参与运算,然后存储到a[i]中,注意此时存储在字符串里的是答案数字

Copy

  1. 处理进位问题

两个数相加后有可能超出10,此时我们需要向前进位。因此接下来我们要进行进位的判断与操作。特别需要注意的是,如果最高位也需要再进一位时,我们在最后输出之前需要添加进位后的数字“1”在答案字符串之前。

for(int i=a.size()-1;i>=1;i--)
{
	if(a[i]>=10)
	{
		a[i-1] += a[i]/10; //先进位
		a[i]% = 10; //进位后剩余的数字
	}
}

Copy

如果最高位需要进位,那么先将进位的答案求出,然后处理a[0]的答案,最后将进位的答案放在最前面连接

if(a[0]>=10)
{
	char t=a[0]/10;
	a[0]%=10;
	a=t+a;
}

Copy

  1. 输出

实现一切之后,我们就可以输出。注意:此时存在字符串里的是答案数字,但由于ASCII码的影响,直接输出会答案错误,因此我们需要将其转换为字符形式才能够正确显示。

for(int i=0;i<a.size();i++)
	cout<<char(a[i]+'0');

Copy

三、高精度减法

高精度减法和高精度加法的原理一样,都是利用“竖式运算”的原理进行处理。

  1. 判断两个谁谁大谁小

如果大数减小数,得到的是正数;如果小的数减大数,相当于调换位置相减,但结果为负。

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

Copy

  1. 高位补 0
int aa=a.size(),bb=b.size();

for(int i=1;i<=a.size()-b.size();i++)
{
	b='0'+b;  //高位补0
}

Copy

  1. 竖式计算,对齐相减
for(int i=a.size()-1;i>=0;i--)
{
	a[i]=(a[i]-’0’)-(b[i]-’0’);  //相减,将答案数字存进字符串a中
}

Copy

  1. 处理借位问题
for(int i=a.size()-1;i>=0;i--)
{
	if(a[i]<0)
	{
		a[i-1]-=1;  //如果是负数,说明不够减,需要向前一位借1
		a[i]=a[i]+10;
	}
}

Copy

  1. 删除前导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
	}
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值