加法:
大整数该如何储存?
用数组储存:
把个位放在数下标为0的位置,十位放在数组下标为1的位置(也就是高位放在数组的后面)
因为这样,如果需要增加一位最高位,那我们就可以直接在vector
数组的最后push_back
最高位到结果数组即可。如果数组低位存的是数的高位,那么我们进行这个操作的时候就需要往后一个一个移动数组,效率很慢。
例题:
#include<bits/stdc++.h>
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];if(i < B.size()) t+=B[i];C.push_back(t % 10);t/=10;//转化为进位数}if(t) C.push_back(t);//如果需要再进位,就需要增加最高位return C;
}
int main()
{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');auto C = add(A,B);for(int i=C.size() - 1;i>=0;i--) cout<<C[i];return 0;
}
减法:
总体思路:
减法和加法一样,是在数组下标小的位置储存位数小的数字。
首先我们需要先判断数字A和数字B的大小,可以从高开始判断。如果大于等于直接计算A-B,否则就计算B-A,添加一个负号。
在执行减法的算法中,我们不难发现如果高位已经为0的时候就会出现前导0,例如100-97=3
,在数组中储存的是003
,所以我们需要去除前导0,恰好前导0刚好在数组的末尾也就是C.back()
。我们只需要循环执行,如果末尾是0就pop()
例题
#include<bits/stdc++.h>
using namespace std;
string a,b;
vector<int> A,B;
bool cmp()//判断A是否>=B
{if(A.size()!=B.size()) return A.size()>B.size();else{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);//如果t<0说明需要借位,t设为1 if(t < 0) t = 1;else t = 0;}//移除前导0,最高位都在数组的最后 while(C.size()>1&&C.back()==0) C.pop_back();return C;
}
int main()
{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');//比较A和B的大小,如果A>B就直接计算A-B的大小,否则就计算B-A,加上一个负号 if(cmp()){auto C = sub(A,B);for(int i=C.size() - 1;i>=0;i--) cout<<C[i];}else{auto C = sub(B,A);cout<<"-";for(int i=C.size() - 1;i>=0;i--) cout<<C[i];}return 0;
}
除法:
整体思路:
-
逐位模拟除法:
手工长除法的核心步骤是逐位计算商和余数。为了实现这种逐位的计算过程,我们从被除数的最高位开始处理。每次将当前处理的数字(即当前位)与前一次计算的余数组合,构成一个新的“被除数”。
-
商和余数的计算:
每次构成新的“被除数”后,将它除以除数,得到商的当前位,余数则留给下一位继续处理。每一位的商计算完成后,商值存储下来,余数用于下一轮的计算。
-
反转商的顺序:
由于我们是从被除数的高位向低位处理,计算过程中得到的商是倒序的(即最低位商最先被计算出)。在最终输出时,需要将计算得到的商反转,才能得到正确的顺序。
-
去除前导零:
计算过程中可能会出现前导零(例如当某些高位不足以大于除数时,商位可能为零)。为了保证输出格式正确,需要在最终输出商时移除这些前导零。
例题:
#include<bits/stdc++.h>
using namespace std;
string a;
int b,r; //r是余数
vector<int> A;vector<int> div() {vector<int> C;//商 for(int i=A.size() - 1;i>=0;i--){r = r*10 +A[i];C.push_back(r / b);r = r % b;}//由于计算过程从低位到高位逐步推进最初得到的结果向量 C 是倒序的(即最高位在最前面)。//为了得到一个正常顺序的结果(即最高位在最后面),需要将 C 中的元素顺序反转reverse(C.begin(),C.end());// 移除结果中的前导零while (C.size() > 1 && C.back() == 0) {C.pop_back();}return C;
}int main() {cin >> a >> b;for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');auto C = div();for(int i = C.size() - 1; i >= 0; i--) cout << C[i];cout<<endl<<r<<'\n';//输出余数 return 0;
}
乘法:
详细思路:
- 逐位相乘:
将被乘数的每一位与乘数逐一相乘,并且从低位开始处理。这相当于我们手工计算乘法时,按位进行乘法运算。
- 进位处理:
每次计算一位的结果时,可能会产生一个进位。例如,计算某一位时结果可能是 13,则当前位为 3,进位 1。这个进位要加到下一位的计算中。
- 移除前导零:
乘法运算可能产生一些前导零,尤其是在乘数是 0 或者被乘数中某些高位为 0 的情况下。我们需要在输出之前移除这些前导零。
例题:
#include<bits/stdc++.h>
using namespace std;
string a;
int b;
vector<int> A;
vector<int> Mul() {vector<int> C;int t = 0;//进位 // for(int i = 0; i < A.size() || t; i++) {if(i < A.size()) t += A[i] * b;C.push_back(t % 10);t /= 10;}// 移除结果中的前导零while (C.size() > 1 && C.back() == 0) {C.pop_back();}return C;
}
int main() {cin >> a >> b;for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');auto C = Mul();for(int i = C.size() - 1; i >= 0; i--) cout << C[i];return 0;
}
解释乘法算法的for循环停止条件
当i
小于A.size()
时,循环继续,处理A
中的每一位数字。
当i
等于或大于A.size()
时,只要t
不为0(即还有未处理完的进位),循环也会继续。这确保了所有的进位都被正确处理,直到没有新的进位产生。