什么是高精度算法?
高精度的意思就是他得名字----高的精度,简单说就是位数很大,而高精度算法就是将这些高精度数(位数很大在几百几千几万位的数叫高精度数)通过计算机的型式模拟出来结果。
为什么要用高精度算法?
我们都知道c++中int的最大值是2^31,unsigned int的最大值是2的32次方,最大的unsigned long long可以到18446744073709551615 。double是浮点型的最大类型,他的最大值是1.7 * 10^308。
这些数据类型对于1+1=2或43545*51345=2235818025这些式子来说绰绰有余,但如果是下面的呢----
153169256934561745635416456903465967693845681963457348+13547477864672672675474676754676783587875372274=? 265464562574318759893457913479346x6524632656224562664=?
3466779657942964574257456/432654724567=?..?
这些式子的数和结果都非常大long long 和 double 都存不下,这时就是要用高精度来计算了
高精度加法
1168:大整数加法
P1601 A+B Problem(高精)
因为不能用计算机直接计算,只能靠模拟。
让我们回顾一下小学一年级时学的加法。
通过这个竖式我们想想是否可以把高精度加法转换成一道让我们模拟加法竖式的模拟题呢?答案是肯定的
带着这个假想我们可以尝试下
首先初始化
注意!!!:因为位数较大所以我们要用字符串或字符数组
const int N=205; //定义大小
string s1,s2; //俩数
int a[N],b[N],c[N]; //存放俩数及结果数组
好了第二步-------读入(read)
void read(){cin>>s1>>s2;
}
好读入结束,等下,这么草草就结束了a,b数组怎么办。
所以为了照顾a,b数组,我们需要把俩字符串数转成整数数组的型式。
但真的是顺着存储吗?不对
如果顺着存储就是这样
本来1257+934的式子竟然变了!而且当你好不容易把他变回去时就会发现如果进位时如123+930数组下标竟然需要负数才能存下那个进位的1了!所以顺着存不行,那试试逆序存呢?
大家可以在草稿纸上试试可以发现,逆着存是可以的,也防止了进位溢出的情况
所以,对于存储s1,s2俩数,应用整数数组逆着存。
void read(){cin>>s1>>s2;int len1=s1.size(),len2=s2.size();for(int i=0;i<len1;i++) a[i]=(s1[len1-i-1]-'0'); //逆序存储。需要字符转整数for(int j=0;j<len2;j++) b[j]=(s2[len2-j-1]-'0');
}
好的终于到模拟部分了
让我们先考虑一下重点
1.考虑进位
2.考虑该进位多少
3.最重要的一点。前导零该怎么办
4.最高位进位
好的一步步来
第一点。因为单个位最大是9,俩9相加才18,进位不可能超1,所以第一部分和第二部分可以同时考虑。如果结果大于10,我们可以将结果-10,或直接不判断直接%10,当然我们也要考虑到当前的i+1位也要+1,所以我们可以用变量来表示这种情况。第三点我们可以从尾开始遍历碰到0就舍去(len-1).如果没碰到就break。第四点我们可以用变量储存模拟完毕后特判下
好分析完毕,代码如下
void count(){int jw=0;len=max(s1.size(),s2.size()); //c的长度是俩数中的最大值或+1for(int i=0;i<len;i++){c[i]=a[i]+b[i]+jw; //求当前结果jw=c[i]/10; //进位数c[i]%=10; //得出当前数} if(jw==1){ //处理最高位进位len++;c[len-1]=1;}while(c[len-1]==0) len--; //去前导零
}
等下考虑下0+0的结果 ,是空,不是0吗,原来当len==1时就算是0也不能舍去
修改如下
void count(){int jw=0;len=max(s1.size(),s2.size());for(int i=0;i<len;i++){c[i]=a[i]+b[i]+jw;jw=c[i]/10;c[i]%=10;} if(jw==1){len++;c[len-1]=1;}while(len>1&&c[len-1]==0) len--;
}
最后到输出部分了,应为开始时是逆序存所以也要逆序输出正所谓负负得正
void print(){for(int i=len-1;i>=0;i--) cout<<c[i];
}
最后总代如下
#include<bits/stdc++.h>
using namespace std;
const int N=205;
string s1,s2;
int a[N],b[N],c[N];
int len;
void read(){ //读入cin>>s1>>s2;int len1=s1.size(),len2=s2.size();for(int i=0;i<len1;i++) a[i]=(s1[len1-i-1]-'0');for(int j=0;j<len2;j++) b[j]=(s2[len2-j-1]-'0');
}
void count(){ //模拟竖式int jw=0;len=max(s1.size(),s2.size());for(int i=0;i<len;i++){c[i]=a[i]+b[i]+jw;jw=c[i]/10;c[i]%=10;} if(jw==1){len++;c[len-1]=1;}while(len>1&&c[len-1]==0) len--;
}
void print(){ //输出for(int i=len-1;i>=0;i--) cout<<c[i];
}
int main(){
read();
count();
print();return 0;
}
另外用结构体来计算大整数加法也是常见的,这里不做多说明了与上文类似
#include<bits/stdc++.h>
using namespace std;
string str;
struct node{ //定义int len,s[205];node(){len=0;memset(s,0,sizeof(s));}
};
node a,b,c;
node operator + (const node&a,const node&b){ //重载加法运算符node c;c.len=max(a.len,b.len);for(int i=1;i<=c.len;i++){c.s[i]+=a.s[i]+b.s[i];c.s[i+1]+=c.s[i]/10;c.s[i]%=10;}if(c.s[c.len+1]) c.len++;return c;
}
node read(){ //读入加去前导零cin>>str;int len=str.size();node a;a.len=len;for(int i=0;i<len;i++){a.s[len-i]=str[i]-'0';}while(a.len>1&&a.s[a.len]==0) a.len--;return a;
}void print(node a){//输出for(int i=a.len;i>=1;i--) cout<<a.s[i];
}
int main(){a=read(),b=read();
c=a+b;
print(c);return 0;
}
高精度减法
1169:大整数减法
与高精度加法类似也是模拟
初始化+读入
string s1,s2;
int a[205],b[205],c[205];
int len;
void read(){cin>>s1>>s2;int n=s1.size(),m=s2.size();len=max(n,m);for(int i=0;i<n;i++){a[i]=s1[n-i-1]-'0';}for(int j=0;j<m;j++){b[j]=s2[m-j-1]-'0';}
}
模拟竖式。
这里也有两项需考虑
1.借位
2.去前导零
第二步相信你们很轻松就能解决。而第一步也很简单我们正常减,如果c[i]<0,那么需要借位了有加就有减,所以c[i]+=10;c[i+1]–;
代码如下
void less(){for(int i=0;i<len;i++){c[i]+=a[i]-b[i];if(c[i]<0){c[i]+=10;c[i+1]--;}}while(len>1&&c[len-1]==0) len--;
}
最后逆序输出
void print(){for(int i=len-1;i>=0;i--) cout<<c[i];
}
总代码
#include<bits/stdc++.h>
using namespace std;
string s1,s2;
int a[205],b[205],c[205];
int len;
void read(){cin>>s1>>s2;int n=s1.size(),m=s2.size();len=max(n,m);for(int i=0;i<n;i++){a[i]=s1[n-i-1]-'0';}for(int j=0;j<m;j++){b[j]=s2[m-j-1]-'0';}
}
void lss(){for(int i=0;i<len;i++){c[i]+=a[i]-b[i];if(c[i]<0){c[i]+=10;c[i+1]--;}}while(len>1&&c[len-1]==0) len--;
}
void print(){for(int i=len-1;i>=0;i--) cout<<c[i];
}
int main(){
read();
lss();
print();return 0;
}
这边结构体减法代码就不放了,有兴趣可以自己做下。
总结下来,只要会高精度加法就会高精度减法。
未完待续。。。。。。