本文已参与「新人创作礼」活动,一起开启掘金创作之路。
大整数:高精度整数,其含义是基本数据类型无法存储其精度的整数。
整数的高位存储在数组的高位,整数的低位存储在数组的低位。不反过来的原因是,在运算的时候都是从整数的低位到高位进行枚举,顺位存储和这种思维相合。
例如:235813 存储在数组中,即有d[0] = 3,d[1]= 1,d[2] = 8, d[3] = 5, d[4] =3, d[5] = 2;
注意: 把整数按字符串%s读入的时候,实际上是逆位存储的,即str[0] =‘2’, str[3] = ‘3’,str[5]= ‘3’,因此在读入之后,需要另存为至d[]数组的时候反转一下。
为了方便获取大整数的长度,一般会定义一个int类变量len来记录其长度,并和d数组合成结构体:
Java有大整数类,没有位数要求
Python默认数范围无限大
仅C++需要
- ,A和B的位数大约是
- ,A和B的位数大约是
- ,大整数乘以小整数,A位数小于等于,a的数值小于等于,这里a可能更小一些,a≤10000
- ,求商和余数
- ,偶尔会考,次数不是很多
- ,偶尔会考,次数不是很多
以上为极端情况,一般不会这么长
一般用数组存储,数据个位存在数组第0位,最高位存在数组末端
思想:根据整数的加法,可以得知:
对其中一位进行加法的步骤:将该位上的数组和进位相加,得到的结果取个位作为该位结果,取十位数作为新的进位。
注意:这样的写法条件:是两个对象都是非负数,如果有一方时负数,可以在转换到数组这一步时去掉符号,然后采用高精度减法;
如果两者都是负的,就都去掉负号后用高精度加法,最后再把负数加回去即可。
#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];
if (i < B.size()) t += B[i];
c.push_back(t % 10);
t /= 10;
}
if (t) c.push_back(1);
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');
auto c = add(A,B);
for(int i = c.size()- 1; i >= 0; i--) printf("%d", c[i]);
return 0;
}
或者写成这种,只判断一个,当A的位数小于B就计算add(B,A)然后返回
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> c;
int t = 0;//进位
for (int i = 0; i < A.size() ; i++)
{
t += A[i];
if (i < B.size()) t += B[i];
c.push_back(t % 10);
t /= 10;
}
if (t) c.push_back(1);
return c;
}
思想:对于某一步,比较被减位和减位,如果不够减,则令被减位的高位减1、被减位加10再进行减法;如果够减,则直接减。
最后一步要注意减法后高位可能有多余的0,要忽略它们,但也要保证结果至少有一位。
#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;
for (int i = 0, t = 0; i < A.size(); i++)
{
t = A[i] - t;
if (i < B.size()) t -= B[i];
c.push_back((t + 10) % 10);
//合并t>0和<0两种情况,大于0则不需要借位,小于0需要向高位借1即10
if (t < 0) t = 1;
else t = 0;
}
while(c.size() > 1 && c.back() == 0) c.pop_back();
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))
{
auto c = sub(A,B);
for(int i = c.size() - 1; i >= 0; i--) printf("%d", c[i]);
}
else
{
auto c = sub(B,A);
printf("-");
for(int i = c.size() - 1; i >= 0; i--) printf("%d", c[i]);
}
return 0;
}
思想:低精度就是可以用基本数据类型存储的数据,例如int型。
以为例,这里147视为高精度bign类型,而35视为int类型。并在下面的过程中,始终将35看成一个整体。
步骤:
- 1,
,取个位数5作为该位结果,高位部分24作为进位;
- 2,
,加上进位24,去各位4作为该位结果,高位进位16作为进位;
- 3,
,加上进位16,得51,取个位数1作为该位结果,高位部分5作为进位;
- 4, 没得乘了,此时进位还不为0,把进位5直接作为结果的高位。
最迂某一步来说这每一步结果:取bign的某位与int型整体相乘,在与进位相加,所得结果的个位数作为该位结果,高位部分作为新的进位。
#include <iostream>
#include <vector>
using namespace std;
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;
c.push_back(t % 10);
t /= 10;
}
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--) printf("%d", c[i]);
return 0;
}
思想:除法的计算方法与小学的是相同的。
以1234/7为例:
步骤:
- 1 1与7比较,不够出,因此该位商0,余数为1;
- 2 余数1与新位2组合成12,12和7比较,够除,商为1,余数为5;
- 3 余数5与新位3组合成53,53与7比较,够除,商为7,余数为4;
- 4 余数4与新位4组合成44,44与7比较,够除,商为6,余数为2。
归纳其中某一步的步骤:上一步的余数乘以10加上该步的位,得到该步临时的被除数,将其与除数比较:如果不够除,则该位的商为0;如果够除,则商即为对应的商,余数即为对应的余数。最后一步要注意减法后高位可能有多余的0,要忽略它,但也要保证结果至少有一位。
#include <iostream>
#include <vector>
#include <algorithm>
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;
}
reverse(c.begin(), c.end());
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--) printf("%d", c[i]);
cout << endl << r << endl;
return 0;
}