目录
1、引入
2、入门思路
3、数的存储
4、高精度加法
5、高精度减法
6、高精度乘法
7、高精度除法
在进行大整数运算中,因为在C++/C中整数,最大也就是unsigned long long也就才(1e19+8e18)位,如果要几百位的相加减就不行了,所以就要用高精度了,这里只在C++/C上使用有价值,在例如python、Java语言上无需写此算法,python可以无限大,Java里有相关库可以引入。
我们如何制作一个算法,让其可以在C++/C中可以进行理论上无限位数的数进行运算,我们试想可以把数存储在数组中,然后根据我们手算的思路,操作数组来进行运算,如下图所示:
这里数的存储呢需要进行逆序存储,因为逆序存储方面进位。以加法为例所示:
我们通过手算的规律可以知道,因为随时可能存在例如(9+1)这的进位,则需要设置一个变量存储是否有进位。如果有进位。那么在下一次运算的时候就加上它,所以可以归结为
t=A[i]+B[i]+t;t初始化为0。
我们算出t之后,t可能>=10,这时候我们只需要个位,然后进1,所以C[i]=t%10;
如果算出是否有进位呢?只需要用t/10判断,因为t<10的时候,t=0;
算法如下:
#include
#include
using namespace std;
vector add(vector &A,vector &B){
if(A.size() C;
for(int i=0;i A,B;
cin >> 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 C=add(A,B);
//返回
for(int i=C.size()-1;i>=0;i--){
cout << C[i];
}
return 0;
}
这里不考虑-10-10等这些负数情况,只考虑正数
高精度减法,我们要考虑到(进1)的情况,则也需要一个t来记录是否需要进1,与高精度加法思路相同,t=A[i]-B[i]-t;但是需要注意的是这里的t可能存在<0和>=0的情况,因为我们这里无法通过代码来通俗的描述进1变十的情况,那么就只能直接A[i]-t-B[i],那么必定会出现负数情况,那该如何存储到C数组中呢,只需要对(t+10)%10,存储即可,可以进行手算验证,这里的t+10呢是防止出现负数情况,如果是正数呢,t+10然后再模10其实就回去了,没有变。如t=3,13%10=3,如果是t=-2,存入的数就为8,这里因为借了十,就加10,也可以这样理解。
那么这里t<0呢,就代表其实是需要进位的,所以就可以写t<0时,t=1;则会t=0;
代码如下:
#include
#include
using namespace std;
bool cmp(vector &A,vector &B){//比较A和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 sub(vector &A,vector &B){
if(!cmp(A,B))cout << '-';
if(!cmp(A,B))return sub(B,A);//如果A不大于B,则转一下
vector C;
for(int i=0,t=0;i1 && C.back()==0)C.pop_back();
return C;
}
int main(){
string a,b;
vector A,B;
cin >> 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 C;
C=sub(A,B);
for(int i=C.size()-1;i>=0;i--){
cout << C[i];
}
return 0;
}
这里我们只考虑大数 X 小数的情况(A[i]xb),也就是b用int存储,在大多场合已经够用了
在高精度乘法中,我们可以把乘数看做一个整体依次相乘被乘数,被除也需要用t标记进位,因为当相乘后需要进行逐次相加,则相加后,我们可以取除了余数的前几项的进位,然后用在下次计算中把t再次加起来。而计算结束的时候也就是没有进位的时候。
设C=(A[i]*b+t)%10;//运算后取模,这里需要把进位也加上去
且t=(t+A[i]*b)/10;//运算后取除最后一项的前几项且加上进位并存储到t变量,为下一次做准备。
、例如:
代码:
#include
#include
using namespace std;
//C = A * b
vector mul(vector &A,int b){
vector C;
int t=0;//进位
for(int i=0;i1 && C.back()==0)C.pop_back();//当b是0时 可能出现多个0,这时候弹出
return C;
}
int main(){
string a;
int b;
vector A;
cin >> a >> b;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
vector C=mul(A,b);
for(int i=C.size()-1;i>=0;i--)cout << C[i];
return 0;
}
注意:除法区别于加法、减法、乘法,除法是从高位计算,这里也是用高精度x低精度
因为除法比较特殊,没有所谓什么进位什么的,因为只会越来越小,除了需要处理前导0。这里只需要一个r变量存储计算过程中的余数就能轻松写出除法代码,因为计算机总是一个数字一个数字的进行扫描,第一位不能商的情况下会商一个0,每次求出r余数的时候,因为在数字没有扫描完全部的时候,都可以进行求商(包括0),程序执行时这样的,
则r=r*10+A[i];
c=r/b//将商存入商数组。
r=r%b;//求每一步的余数
例如:
代码:
#include
#include
#include
using namespace std;
vector div(vector &A,int &b,int &r){
vector C;
r=0;
for(int i=A.size()-1;i>=0;i--){//高位开始,区别于加减乘
r=r*10+A[i];
C.push_back(r/b);
r%=b;
}
reverse(C.begin(),C.end());//注意:算出的结果也是正序的,这里翻转是因为需要去掉前导0.且与加减乘相对应;
while(C.size()>1 && C.back()==0 )C.pop_back();
return C;
}
int main(){
string a;
int b,r;
vector A;
cin >> a >> b;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
vector C=div(A,b,r);
for(int i=C.size()-1;i>=0;i--)cout << C[i];
cout << endl << r;
}