高精度计算(10进制)
数据接收和存储
当我们输入的数很长的时候,我们可以采用字符串的形式输入,然后再讲字符串的每一位取出放进数组中
string a;
vector<int> A;//变长数组
cin>>a;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
//数组第i位存的就是数的第i位
高精度加法
用一个变量t存当前位的和,然后对10取模 多的攒到下一位
#include <iostream>
#include <vector>
using namespace std;
vector<int> add(vector<int> &A,vector<int> &B)
{
vector<int> c;
int t=0;
for(int i=0;i<A.size()||i<B.size();i++)//读每一位
{
if(i<A.size())t+=A[i];//如果A有第i位
if(i<B.size())t+=B[i];//如果B有第i位
c.push_back(t%10);//就把和结果对10取模放到c
t/=10;//多出的攒到下一位
}
if(t)c.push_back(t);//最后一位相加有进位
return c;
}
int main(void)
{
string a,b;
cin>>a>>b;
vector<int> A,B;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
vector<int> C=add(A,B);
for(int i=C.size()-1;i>=0;i--)cout<<C[i];
return 0;
}
高精度减法
这里默认是A大于B所以模板就是A-B,如果B大于A我们要特别判断
所以新增cmp函数思路是 比较长度 长度不相等 长的就是较大的
从高位往低位比较 不同的那一位那个大一点整体就大
上面都不是那就相等
高精度减法:用一个变量t记录借位 然后用A当前位减去借位继续存t中
如果B也有当前位那么t就减去B的当前为t的结果就是当前位运算的结果
t=A[i]-t-B[i];//注意等号右边的t是借位1 然后赋值给等号左边t是暂时存储的变量
该模板试用于前面没有正负号的减法 如果有 需要自己先处理
模板是默认A>B 所以A<B先B-A再加负号
然后(t+10)%10是简写 因为当前位相减结果后t>0 那么就是t 如果t<0 就要向前一位借10
/(t+10) %10就是借后相减结果 如果结果本来大于0了 那么(t+10) %10 没有影响
然后判断 t<0 就是借1位 其他情况不用借 t=0;
打个标记(x+M)%M 以后还会遇到的奥(保持正数 偏移)
#include <iostream>
#include <vector>
using namespace std;
bool cmp(vector<int> &A,vector<int> &B)
{
if(A.size()!=B.size())return A.size()>B.size();
for(int i=A.size()-1;i>=0;i--)
if(A[i]!=B[i])return A[i]>B[i];
return true;
}
vector<int> sub(vector<int> &A,vector<int> &B)
{
vector<int> c;
int t=0;
for(int i=0;i<A.size();i++)//从低位往高位减起!
{
t=A[i]-t;
if(i<B.size())t-=B[i];
c.push_back((t+10)%10);
/*
------
如果当前位相减的结果小于零 我们就要往前借一位 原本不够的是复数借位后+10即可
如果当前为相减结果大于零 说明不需要借位 +10再模10没有影响
------
*/
if(t<0)t=1;//有借位 下一位就减1
else t=0;//没有借位就不用
}
while(c.size()>1&&c.back()==0)c.pop_back();
//去掉前导零 比如结果0000 只留下个位0
return c;
}
int main(void)
{
string a,b;
cin>>a>>b;
vector<int> A,B,C;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
if(cmp(A,B)) C=sub(A,B);
else cout<<'-',C=sub(B,A);
for(int i=C.size()-1;i>=0;i--)cout<<C[i];
return 0;
}
高精度乘法(模拟乘法竖式运算)
高精乘低精
#include <iostream>
#include <vector>
using namespace std;
//高精度乘法 (这里全部默认自然数(>=0)) 符号问题自己解决
//
vector<int> mul(vector<int> &A, int b) {
vector<int> c;
int t = 0;
for (int i = 0; i < A.size() || t; i++) {
if (i < A.size())
t += A[i] * b; //999*99=99*(900+90+9)当前行是当前位上的数与较小数b 相乘结果
//当前位结果是t%10
//剩下的进位t/=10;
//t还有要进位的就进位
c.push_back(t % 10);
t /= 10;
}
while (c.size() > 1 && c.back() == 0)
c.pop_back();//乘0的话只留一个零
return c;
}
int main(void) {
string a;
int b;
cin >> a >> b;
vector<int> A;
for (int i = a.size() - 1; i >= 0; i--)
A.push_back(a[i] - '0');
auto c = mul(A, b);
for (int i = c.size() - 1; i >= 0; i--)
cout << c[i];
return 0;
}
高精乘高精
参考以下图片
#include <iostream>
#include <vector>
using namespace std;
vector<int> mul(vector<int> &A,vector<int> &B)
{
int t=0;
vector<int> c(A.size()+B.size());//乘法不会超过两个数位相加
for (int j = 0; j < B.size(); j ++ )
for (int i = 0; i < A.size(); i ++ )
c[i+j]+=B[j]*A[i];
/*
这里用乘法交换律换一下顺序好看一点 我写的是模拟A*B的可以写成B*A的
for (int i = 0; i < A.size(); i ++ )
for (int j = 0; j < B.size(); j ++ )
c[i + j] += A[i] * B[j];
*/
for(int i=0;i<c.size();i++)
{
t+=c[i];
c[i]=t%10;
t/=10;
}
while(c.size()>1&&c.back()==0)c.pop_back();//去掉前导零
return c;
}
int main(void)
{
string a,b;
cin>>a>>b;
vector<int> A,B;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
vector<int> c=mul(A,B);
for(int i=c.size()-1;i>=0;i--)cout<<c[i];
return 0;
}
高精除低精
高精度除法 (这里是模拟/法 整除 向下取整)(正负问题自己解决)
r是余数 然后思路就是 r=当前位+前一位的余数*10为用来除的数 然后r/b就是结果
r%b就是算完后相见的那一步的结果 就是变成下一位的前一位的余数
然后统一 就翻转一下 高位存在后面 然后去掉前导零
#include <bits/stdc++.h>
using namespace std;
vector<int> div_(vector<int> &A,int &b,int &r)
{
vector<int> c;
r=0;
for(int i=A.size()-1;i>=0;i--)
{
r=r*10+A[i];
c.push_back(r/b);
r%=b;
//模拟除法 31除以8 3/8不够除 然后第一位结果0 r存的也是0*10+3 然后c放3/8==0
//然后除完第一位就余3 第二位3*10+1 31/8==3 余7 结束 r就是存除哪一位后的余数
//r一开始是0 然后最后就是整个数除完的余数
}
reverse(c.begin(),c.end());//让个位存在数组第一位...
while(c.size()>1&&c.back()==0) c.pop_back();
//去掉前导零
return c;
}
int main(void)
{
string a;
int b;
cin>>a>>b;
vector<int> A;
int r=0;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
auto c=div_(A,b,r);
for(int i=c.size()-1;i>=0;i--)cout<<c[i];
cout<<endl<<r;
return 0;
}