引入
高精度算法是一种模拟算法,主要的作用就是当我们的数据足够大的时候(int 和 long long)都存不下来的时候,仍然可以正确的运算并输出结果。
它是一个最入门的算法,数学基础是小学二年级的加减乘除运算以及其竖式运算。
我们这个系列专栏学习的目标程度是将高精度算法成功的封装好。
算法实现过程
假设有两个高精数,A,B,需要我们去实现他的加减乘除运算,最后正确地输出结果。
第一步,我们要使用计算机去运算,首先要先定义(申请空间)A、B两个数。
问题1:按照计算机的存储数字的原理,都是把十进制数转换为了二进制数,再存储到计算机的物理空间之上:
(常规地输入整数a)
#include<iostream>
using namespace std;
int a;
int main()
{
cin>>a;
return 0;
}
可是,int(4字节)long long(8字节)都没法存下一个成百上千位的高精数。这个时候,我们就要投机取巧了,我们不把十进制数转为二进制数存储,而把它用数组来存起来。
但是,这个时候问题又来了。在C++标准输入中,我们输入数组的时候都需要将数以空格隔开:
1 2 3 4 5 6 7 8 9 0
而我们的目标输入方式:
1234567890
所以,我们引入了字符串:
我们先定义一个字符串,并将数输入进去,以字符串的形式存储。然后再正序导入到数组当中去。我们用两个int变量来记录A、B两数的长度。
假设a=99991,b=9;
int main()
{
string a,b;
int lena,lenb;
int a1[1001],b1[1001];
cin>>a>>b;
lena=a.size(),lenb=b.size();
for(int i=lena-1;i--;i>=0) a1[lena-i]=a[i];
for(int i=lenb-1;i--;i>=0) b1[lenb-i]=a[i];
}
跳跳跳跳跳~~~~
<当前状态为已经向上面那样正序存入数组>我们现在开始运算了,99991+9=????
输出:10000
这个数怎么越变越小了???
这说明我们还是没有能够使我们的存储方式能够满足高精度的运算。分析一下刚刚的那个情况,明显是少了一位-个位的‘0’。为什么会少输呢?这是因为我们没有能够预估到结果的位数有多少。
那么我们就来介绍估计位数的算法。(根本就没有)
所以我们就倒序存储这个数吧,这样就使得我的数组不会溢出,不会损失数据。(具体编码实现请看下一篇文章)
问题2:我现在已经输入并存储了A、B两个数了,下面就开始运算了。
我们的运算过程和竖式运算很相似,除法除外,总共会涉及到两个操作:运算和进位。
所以我们在加减乘运算之前都需要定义一个专门进位的
int x=0;
初始化为 0 。
以加法为例:
我们都知道一个数加另一个数的结果的位数至少是两数当中的位数最大的数。
我们定义一个c数组来存储结果
int c[1001];
int lenc=max(lena,lenb);
证明:举极端例子:10000+1=10001,结果的位数永远不会低于两数中位数最大的那个数的位数
sure,负数另当别论。
然后就是通过构建循环来进行计算:
循环lenc次遍历两个数,个位对个位,十位对十位,然后相加。从低位到高位,每次相加一次,x更新一次,同时每次相加都会连带x一起加。
c[i]=a[i]+b[i]+x;
x=c[i]/10;
c[i]%=10;
之前最后我们再来一个特判,如果我们的结果的前lenc位都已经算出了,那么我们还应该考虑一下是否第lenc+1位为 0 。
如果是 0 ,那么我们就不用去管它,不是 0 ,我们就需要吧第lenc+1位给它添上:
if(x!=0) lenc=lenc+1,c[lenc]=x;
(本文为了对新手友好,一些更晦涩简洁的写法被修改为了冗长但更易于理解的写法)
问题3:输出这个结果。
输入说了那么多,输出其实已经没有太多需要解释的地方了。
将c数组又倒序输出:
这一下,结果终于对啦!
输出:100000
新人写作,还请各位神犇多多指导!