高精度的加、减、乘、除运算-C++实现
算法基本思想及步骤
1.用可变数组储存大整数,从低位到高位依次存储
2.模拟人工加、减、乘、除法运算过程
AcWing题库-791-高精度加法
题目
给定两个正整数,计算它们的和。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的和。
数据范围
1≤整数长度≤1000000
输入样例
12
23
输出样例
35
思路解析:
高精度的运算,都采取先用字符串存储再转存入vector可变数组中,这里注意需要倒着存,因为我们手工运算加法的时候一般从低位到高位开始算,而数字存储一般先存高位再存低位,所以我们这里倒着先存低位再存高位,以便运算的时候需要向上进位。当要运算的数字分别存入 A 和 B 中后,就可以依次开始运算了,想象我们手工算加法的时候,从低位开始,将 A 和 B 的每一位数字对齐,依次相加,多的就向前进位,转移到代码上就是循环遍历 A 和 B 的每一位,这里就需要引入一个中间值 t ,因为我们需要判断每次相加后的值需不需要进位,且需要将得到的结果一位一位地存入结果数组 C 中,所以先把 A[i] 加上 B[i] 的值存入 t 中,因为不知道需不需要进位,所以可直接将 t % 10 的值加入 C 中,不管进不进位,t % 10得到的都一定是结果数组中这一位的值,然后再将 t / 10 ,如果 t < 10 ,这里得到的 t 就是 0 ,也就是说没有进位,如果 t > 10 ,得到的 t 就是 1 ,也就是说进位是1,在下一次循环运算的时候直接将 t 的值加进 A[i] 和 B[i] 的和里就行了。以此类推,在最后退出循环后再判断一次 t 的值确定是否最高位需要进位就得到了结果数组 C ,输出的时候再倒着输出就可以了。
代码
#include <iostream>
#include <vector>
using namespace std;
//C = A + B, 满足A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
vector<int> C;
if (A.size() < B.size()) return add(B, A); //确保A的长度大于B,便于计算
int t = 0;
for (int i = 0; i < A.size(); i++)
{
t += A[i]; //将上一次计算的进位数t也加进去
if (i < B.size()) t += B[i]; //如果B已经加完了就只用加A的数
C.push_back(t % 10); //如果逐位相加的和大于10,将个位输入给C
t /= 10; //逐位相加的和的十位进位给下一位
}
if (t) C.push_back(1); //若最后得到的t不为0,则向最高位前进位
return C;
}
int main()
{
string a, b;
vector<int> 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');//利用数字字符减去'0'得到数字储存在数组中
vector<int> C = add(A, B);
for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
cout << endl;
return 0;
}
AcWing题库-792-高精度减法
题目
给定两个正整数,计算它们的差。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的差。
数据范围
1≤整数长度≤10^6
输入样例
32
11
输出样例
21
思路解析:
高精度减法与高精度加法的存储方式一样,也是倒着存,但需要注意模板的代码只能用大数减小数,所以需要对被减数和减数的大小进行一个判断,如果被减数小于减数就让其对调,给结果加一个负号。减法的中间值t 需要完成的工作是存储每一位依次相减时向前借的位,也就是在计算 A[i] - B[i] 前先让 A[i] 减去 t ,减完之后由于不知道 t 是不是正数,可直接把 (t + 10) % 10 存入 C 中,直接提前借位,不管 t 是大于 0 还是小于 0 都能把结果数组中这一位的正确数字存进去,之后再进行判断,如果 t < 0 ,也就是需要向前借位,就令 t = 1 ,等到下一位运算的时候就能直接把借的位减掉,如果 t > 0 ,也就是不需要向前借位,就令 t = 0 ,对下一位运算无影响。由于运算的时候并没有判断如果最高位出现 0 该怎么办,所以在循环结束后需要加一个判断以消去最高位的 0 。最后,输出的时候仍然是倒着输出。
代码
#include <iostream>
#include <vector>
using namespace std;
//比较A、B大小
bool cmp(vector<int> &A, vector<int> &B)
{
if (A.size() != B.size()) return A.size() > B.size();
//若A、B长度不相同,则设置比较条件为A和B的长度
for (int i = A.size() - 1; i >= 0; i--)
{
if (A[i] != B[i])
return A[i] > B[i];
//若A、B长度相同但A不等于B,则设置比较条件为从最高位开始A和B不相同的那一位
}
return true; //若A、B相等,则不管谁减谁都一样
}
//C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
vector<int> C;
for (int i = 0, t = 0; i < A.size(); i ++ )
{
t = A[i] - t; //先减去上一次运算借的位
if (i < B.size()) t -= B[i]; //如果B被减完了就只需要保留A这一位的数
C.push_back((t + 10) % 10); //若中间值为负,则将借位后的差存入C,若中间值为正,直接将其存入C
if (t < 0) t = 1; //若t为负,则借位为1
else t = 0; //若t为正,则不需要借位
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); //消去C中最高位可能出现的0
return C;
}
int main()
{
string a, b;
vector<int> 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');
if (cmp(A, B)) //保证一定是大数减小数
{
vector<int> C = sub(A, B);
for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
cout << endl;
}
else
{
vector<int> C = sub(B, A);
cout << "-"; //若A小于B,求B-A的值,在结果前添加负号
for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
cout << endl;
}
return 0;
}
AcWing题库-793-高精度乘法
题目
给定两个正整数A和B,请你计算A*B的值。
输入格式
共两行,第一行包含整数A,第二行包含整数B。
输出格式
共一行,包含A*B的值。
数据范围
1≤A的长度≤1000000
1≤B≤10000
输入样例
2
3
输出样例
6
思路解析:
注意高精度乘法和除法模板是对于一个大数和小数的乘除,也就是小数的范围是在1~10000,远小于大数,所以对于小的这个数就不用采用字符串的方式输入,可以直接获取。对于乘法采取用大的数的每一位分别乘以小的数,中间值 t 即为每次乘完需要进位的值,每次循环运算时,需要将上一次运算进的位 t 加入A[i] * b 的结果中,再把得到的结果的个位存入结果数组 C 中,即 t % 10,最后删去个位(即 t /= 10),剩下的就是需要向前进的位。注意循环完也要删去高位 0 。
代码
#include <iostream>
#include <vector>
using namespace std;
//C = A * b,满足A >= 0, b > 0
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;
int t = 0;
for (int i = 0, t = 0; i < A.size() || t; i ++ )
//如果已经算到最高位但进位不为0,仍然要继续循环
{
if (i < A.size()) t += A[i] * b; //只要没算到最高位就还需要乘以b
C.push_back(t % 10); //t的个位即为当前位置的结果数
t /= 10; //t删去个位,即为需要进的位
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); //消去C中最高位可能出现的0
return C;
}
int main()
{
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');
vector<int> C = mul(A, b);
for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
cout << endl;
return 0;
}
AcWing题库-794-高精度除法
题目
给定两个正整数A,B,请你计算A/B的商和余数。
输入格式
共两行,第一行包含整数A,第二行包含整数B。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤1000000
1≤B≤10000
输入样例
7
2
输出样例
3
1
思路解析:
除法仍然是较小的数直接输入,较大的数用字符串转换为可变数组,由于除法的计算方式是从高位向低位逐个除,所以在输入的时候不用倒着输,直接按原顺序输入即可。因为除法需要得到的数多了一个余数,所以参数传递的时候也多了一个余数 r ,而且除法在计算的时候,每次高位除完得到的余数需要与下一位合并,所以这里的中间值也是余数 r ,在循环中,因为每次余数的位数相对于下一位的位数靠前一位,所以每次合并余数和被除数的时候需要将余数乘以10再加上下一位数字 A[i] ,结果数则可以直接用整数除法计算式,即存入 r / b ,最后再将 r 转换成当前位数字除完的余数即可(即 r % b )。注意这里C的存储方法是从高位到低位,所以去掉高位0的时候需要先将C前后翻转,最后将C倒着输出即可。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//A / b, 商是C,余数是r
vector<int> div(vector<int> &A, int b, int &r)
{
vector<int> C;
r = 0;
for (int i = 0; i < A.size(); i ++)
{
r = r * 10 + A[i]; //余数与下一位被除数合并
C.push_back(r / b); //存入当前位的商
r %= b; //使r变为当前位的余数
}
reverse(C.begin(), C.end());
while (C.size() > 1 && C.back() == 0) C.pop_back(); //去掉高位0
return C;
}
int main()
{
string a;
int b, r;
vector<int> A;
cin >> a >> b;
for (int i = 0; i < a.size(); i ++) A.push_back(a[i] - '0');
vector<int> C = div(A, b, r);
for (int i = C.size() - 1; i >= 0; i --) cout << C[i];
cout << endl << r << endl;
return 0;
}
(模板来源于AcWing算法基础课)