高精度算法
高精度加法
-
大整数存储:为了方便进位,数的最高位存在数组的末端(push_back()),数组下标从0开始存储的是该数从个位到最高位。
-
运算:模拟人工加法的过程,对应数相加(结果取模),逢十进一(Ai + Bi + 进位)。巧妙:用t来记录Ai + Bi + 进位的总和
#include<iostream>
#include<vector>
using namespace std;
const int N = 100000+10;
vector<int> add(vector<int> &A, vector<int> &B)
{
//保证大的数在上方(符合现实加法计算)
if(A.size() < B.size()) return add(B,A);
vector<int> C;//用来存储结果
int t = 0;// 初始进位为0
//遍历求和
for(int i = 0; i < A.size(); i++)
{
t += A[i];
if(i < B.size()) t += B[i];
//执行到这里t里记录A和B数组对应位以及进位的和 Ai + Bi + 进位
C.push_back(t % 10);//记录结果
//进位
t = t / 10;
}
//判断最后一位求和后要不要进位
if(t) C.push_back(1);
return C;
}
int main()
{
string a, b;
//a = "123456"
//将大整数用数组存下来(vector)
vector<int>A, B;
cin>>a>>b;
//a[i] - '0'将字符a[i]转为整数
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0'); //A = [6,5,4,3,2,1];
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;
}
注:
- 数不知道多大用string来输入(int 的范围有限)
- 存储时用vector:动态大小、方便进位操作(利用push_back(),将最高位放到后面)
- 因为输入的是string类,在存入数组时要将字符(每一位)转为整数(
字符 - '0'
)- 返回结果是vector(数组),因此函数类型是vector< int >
- 为了加快效率添加引用符
&
:add(vector< int > &A, vector< int > &B)- if(t) C.push_back(1);判断最后一位求和后要不要进位。如(411 + 811 最后一位8 + 4=12如果没有进位1则答案只有A.size()个数,答案并不完整)
高精度减法
1、定义存储数组:大整数存储同高精度加法
2、被减数和减数确认。由于减法可能出现负数(3-5 = -2 ---> - (5 - 3)
)。
3、读入数据到数组中。注意:保证被减数大于减数;(A>=B ---> cmp(A,B)
)
4、从个位开始模拟竖式减法的过程,完成整个减法。
5、差值为>=0或者<0两种情况(<0则需要借位)
6、删除前导 0 。所谓前导零,就是出现类似这样数据 01234,这个 0 实际是不需要的。(注:当相等的两数相减的结果0,它不是前导0
)
7、输出减法的结果。倒序输出减法的结果数组 C,因为我们的个位是存储在下标为 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();
//长度一样:从最高位开始逐一比较判断,不相等,高位大的就大;都相同则相等
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)
{
int t = 0;
vector<int> C;
for(int i = 0; i < A.size(); i++)
{
t = A[i] - t;
if(i < B.size()) t -= B[i];// 到这里此时得到的是Ai - Bi的结果,t记录两数之差(大于/小于0)
C.push_back((t + 10) % 10);//记录答案(包含了差 >=0 和 <0 两种情况)
if(t < 0) t = 1; // 差结果t<0 则借一位
else t = 0;// t > 0则不借位
}
//除去前导0
//注:C.size() > 1,而不是>0 (4-4 = 0 size = 1,若是>0 4-4 = 0的结果0就会被删去了)
while(C.size() > 1 && C.back() == 0) C.pop_back();
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');
//判断A,B大小
if(cmp(A,B)) // A > B
{
auto C = sub(A,B);
for(int i = C.size() - 1; i >= 0; i--)
cout<<C[i];
}
else // A < B
{
auto C = sub(B,A);
cout<<"-";
for(int i = C.size() - 1; i >= 0; i--)
cout<<C[i];
}
return 0;
}
高精度乘法
高精度X低精度
存储:高精度以字符串形式输入保存(同上),低精度以整数形式输入即可
运算:不是我们认为的模拟乘法。把b看成一个整体,而不是一位一位的乘
#include<iostream>
#include<vector>
using namespace std;
// a * 整体b
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;
//用t来记录乘积结果以及进位
int t = 0;
for(int i = 0; i < A.size() || t; i++) // i没有循环完或者t不为0
{
if(i < A.size())
{
t += A[i] * b; // 用t来记录乘积结果
C.push_back(t % 10); // 记录答案
}
else
{
C.push_back(t % 10); //若t不为0 记录最高位答案
}
t = t / 10; // 进位
}
//去除前导0(当b为0时)乘以0的时候,就会有前导0,如 123 x 0=000
while(C.size() > 1 && C.back() ==0) C.pop_back();
return C;
}
int main()
{
string a;
int b;
vector<int> A;
cin>> a>> b;
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;
}
for(int i = 0; i < A.size() || t; i++) // i没有循环完或者t不为0。 关于|| t理解
比如一个三位数乘二位数可能会有等于四位数(进位)的情况,而如果没有||t的话,C的长度最长就是三,||t就是用来储存A的最高位和b相乘的结果
注:
在for循环的条件判断语句中,首先执行i =0;再执行判断语句,如果条件判断为真,则执行for循环中的内容,最后对i进行加1操作。然后依次循环进行判断,代码段和i++中的内容。
高精度X高精度
- 相乘累加(乘法交换律)
- 进位求余
#include <iostream>
#include <vector>
using namespace std;
vector<int> mul(vector<int> &A, vector<int> &B)
{
vector<int>C(A.size() + B.size());
//相乘累加
for(int i = 0; i < A.size(); i++){
for(int j = 0; j < B.size(); j++){
C[i + j] += A[i] * B[j];
}
}
//进位求余
int t = 0;
for(int i = 0; i < C.size() || t; i++) // i没有循环完或者t不为0
{
if(i < C.size())
{
t += C[i];
C[i] = t % 10; // 记录答案
}
else C.push_back(t % 10); // t不为0时,记录最高位
t = t / 10; // 进位
}
//清除前导0
while(C.size() > 1 && C.back() == 0) C.pop_back();
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 = mul(A, B);
for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
cout << endl;
return 0;
}
高精度除法(高精度 除 低精度)
存储方式:同前
运算:模拟手算除法,但是一位一位的除
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> div(vector<int> &A, int b, int &r)
{
r = 0; // 初始剩余的数为0
vector<int> C;
//从最高位开始除
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;
cin>>a>>b;
vector<int>A;
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
int r;
auto C = div(A,b,r);
for(int i = C.size() - 1; i >= 0; i-- )
cout<<C[i];
cout<<endl<<r;
return 0;
}
总结:
- 四种存储以及输出方式一致
- 除了高精度加法其它三种都要去除前导0