title: 高精度算法(c++版)
date: 2019-05-23 09:56:21
tags: 高精度
高精度算法
高精度加法
每次记得加 进位t 就行
#include <iostream>
#include <cstring>
#include <vector>
const int maxn=1e7+5;
using namespace std;
vector<int> aa,bb;
//c=a+b
vector<int> add(vector<int> &aa,vector<int> &bb)//这里加上&是为了防止把aa copy一遍,不拷贝整个数组就会快很多
{
vector<int> cc;
int t=0;//进位 初始时最低位进位为0
for(int i=0;i<aa.size()||i<bb.size();i++)//任一个字串长度,其实取一个max就可以了
{
if(i<aa.size())
t+=aa[i];
if(i<bb.size())
t+=bb[i];//此时 一位上的 t=a+b+t
cc.push_back(t%10);//对应和的这一位的数有了
t/=10;//向更高一位的进位
}
if(t)//最高位如果还有进位,记得在末尾再加一位
cc.push_back(t);
return cc;
}
int main()
{
string a,b;
cin>>a>>b;//12345
for(int i=a.size()-1;i>=0;i--)
aa.push_back(a[i]-'0'); //54321
for(int i=b.size()-1;i>=0;i--)//因为考虑到最高位进位的问题,所以让个位在最前面比较好,这样只需要在最后一位加上进位数字即可
bb.push_back(b[i]-'0');
auto cc=add(aa,bb);
for(int i=cc.size()-1;i>=0;i--)//注意要倒着输出
printf("%d",cc[i]);
cout<<endl;
return 0;
}
高精度减法
每次要保证
A-B时
如果A>=B --> A-B
如果A<B --> - (B-A)
注意一下前导0的处理
#include <iostream>
#include <cstring>
#include <vector>
const int maxn=1e7+5;
using namespace std;
vector<int> aa,bb;
//判断是否有aa>=bb
bool cmp(vector<int> &aa,vector<int> &bb)
{
if(aa.size()!=bb.size())
return aa.size()>bb.size();
for(int i=aa.size()-1;i>=0;i--)
{
if(aa[i]!=bb[i])
return aa[i]>bb[i];
}
return true;//相等
}
//cc=aa-bb
vector<int> sub(vector<int> &aa,vector<int> &bb)
{
vector<int> cc;
int t=0;
for(int i=0;i<aa.size();i++)//这里我们保证aa大于bb,从个位开始处理
{
t=aa[i]-t;//t=aa[i]-bb[i]-t; 但是我们要看bb[i]有没有这一位
if(i<bb.size())
t-=bb[i];
cc.push_back((t+10)%10);//因为t可能是个负数,不够减的时候向高位借1 +10
//这种写法可以涵盖t是正或负数两种情况
if(t<0)
t=1;//向高一位借了1 要减掉
else
t=0;
}
//这里还要特别注意去掉前导0 比如 123-120=003
while(cc.size()>1&&cc.back()==0)//还要注意 如果结果为0,最后要留一个0
//cc.back() 表示cc的最后一个是0
{
cc.pop_back();
}
return cc;
}
int main()
{
string a,b;//注意这里如果有负数在运算中 我们可以设定标记判断 总之一定可以变成绝对值相加或者绝对值相减的
//特殊处理一下输入输出即可
cin>>a>>b;//12345
for(int i=a.size()-1;i>=0;i--)
aa.push_back(a[i]-'0'); //54321
for(int i=b.size()-1;i>=0;i--)//因为考虑到最高位进位的问题,所以让个位在最前面比较好,这样只需要在最后一位加上进位数字即可
bb.push_back(b[i]-'0');
vector<int> cc;
//注意这里要判断一下aa,bb谁大
if(cmp(aa,bb))
cc=sub(aa,bb);
else
{
cc=sub(bb,aa);
printf("-");
}
for(int i=cc.size()-1;i>=0;i--)//注意要倒着输出
printf("%d",cc[i]);
cout<<endl;
return 0;
}
高精度乘法
取每一位去*b,然后做带进位t的加法
#include <iostream>
#include <vector>
using namespace std;
vector<int>aa;
vector<int> mul(vector<int> &aa,int bb)
{
vector<int> cc;
int t=0;
/*或者 简单点 这样
for(int i=0;i<aa.size()||t;i++)
{
if(i<aa.size())
t+=aa[i]*bb;
cc.push_back(t%10);
t/=10;
}
*/
for(int i=0;i<aa.size();i++)
{
t+=aa[i]*bb;
cc.push_back(t%10);
t/=10;
}
while(t) //也可以直接在上面加||t
{
cc.push_back(t%10);//还要注意这个tt可能不止一位数 不过 为什么这个cc的一位不能放两位数以上??会爆内存?
t/=10;
}
return cc;
}
int main()
{
string a;
int bb;
cin>>a>>bb;
for(int i=a.size()-1;i>=0;i--)
aa.push_back(a[i]-'0');
auto cc=mul(aa,bb);
for(int i=cc.size()-1;i>=0;i--)
printf("%d",cc[i]);
cout<<endl;
return 0;
}
高精度除法
#include <iostream>
#include <algorithm>
#include <vector>
const int maxn=1e6+5;
using namespace std;
vector<int> aa;
//cc=aa/bb
vector<int> div(vector<int> &aa,int bb,int &r)
{
vector<int> cc;
r=0;
//注意 除法是从最高位开始算
for(int i=aa.size()-1;i>=0;i--)
{
r=r*10+aa[i];
cc.push_back(r/bb);
r%=bb;
}
reverse(cc.begin(),cc.end());//因为 在main函数中是倒着输出的,所以这里要reverse一下,本来可以就直接顺着输出cc的
//这里还要特别注意去掉前导0
while(cc.size()>1&&cc.back()==0)
cc.pop_back();
return cc;
}
int main()
{
string a;
int bb;
cin>>a>>bb;
for(int i=a.size()-1;i>=0;i--)
aa.push_back(a[i]-'0');
int r;
auto cc=div(aa,bb,r);
for(int i=cc.size()-1;i>=0;i--)
printf("%d",cc[i]);
cout<<endl<<r<<endl;
}
压位
可以加速
加法可以压9位,乘法一般压4位 (因为如果5位 (10^5^)^2^会爆int)
#include <iostream>
#include <cstring>
#include <vector>
const int maxn=1e7+5;
using namespace std;
vector<int> aa,bb;
const int base=1e9;
//c=a+b
vector<int> add(vector<int> &aa,vector<int> &bb)//这里加上&是为了防止把aa copy一遍,不拷贝整个数组就会快很多
{
vector<int> cc;
int t=0;//进位 初始时最低位进位为0
for(int i=0;i<aa.size()||i<bb.size();i++)//任一个字串长度,其实取一个max就可以了
{
if(i<aa.size())
t+=aa[i];
if(i<bb.size())
t+=bb[i];//此时 一位上的 t=a+b+t
cc.push_back(t%base);//对应和的这一位的数有了
t/=base;//向更高一位的进位
}
if(t)//最高位如果还有进位,记得在末尾再加一位
cc.push_back(t);
return cc;
}//主要改的是/base
int main()
{
string a,b;
cin>>a>>b;//12345
for(int i=a.size()-1,s=0,cnt=0,t=1;i>=0;i--)//数据处理要注意
{
//s=s*10+a[i]-'0';//因为是倒着输入的,所以要注意这里
s+=(a[i]-'0')*t;
cnt++;
t*=10;
if(cnt==9||i==0)
{
aa.push_back(s);
s=cnt=0;//里面要注意重新初始化
t=1;
}
}
//aa.push_back(a[i]-'0'); //54321
for(int i=b.size()-1,s=0,cnt=0,t=1;i>=0;i--)//因为考虑到最高位进位的问题,所以让个位在最前面比较好,这样只需要在最后一位加上进位数字即可
{
//s=s*10+a[i]-'0';
s+=(b[i]-'0')*t;
cnt++;
t*=10;
if(cnt==9||i==0)
{
bb.push_back(s);
s=cnt=0;
t=1;
}
}
//bb.push_back(b[i]-'0');
auto cc=add(aa,bb);
cout<<cc.back();
for(int i=cc.size()-2;i>=0;i--)//注意要倒着输出
printf("%09d",cc[i]);//高位不足9位要补0
cout<<endl;
return 0;
}