高精度是什么意思
在计算机中,高精度的意思是指 一个数特别特别大,最大可以有 10的5次方 个 位数 ,注意是有这么多位数,而不是 10的五次方 大。
两个高精度数字的加法
下面来求两个超级超级大的数字相加。
本次实现两个数字均为正整数,求负数的会在高精度减法的时候讲到。
思路实现
我们先来模拟一下人类是怎么实现加法的。
首先是计算个位数,由于5 + 9 = 14 ,14 > 10 所以要进一位,个位是4。
同理后面思路一样。
代码实现
由于没有数据类型能够存这么大的数字,所以我们需要用到数组来存储每一位。
又由于 不能直接读取数字 将每一位放到数组中,所以我们得利用字符串先读取,然后再遍历字符串将每一位放到数组中。
所以我们先创建两个字符串,然后读取两个数字
接下来需要将字符串的每一位放到数组当中。
由于vector容器不需要自己手动记录 数组当中有效数据的个数,所以我们使用vector容器。
接下来遍历字符串,将每一位存到数组当中。
注意:字符串的每一位都是字符,所以在放到数组当中的时候一定要 减去 ‘0’(字符0).
这里你会发现我们是倒着存的,数字的个位放在了数组中的第一位。
这是因为由于数组后端插入值比较方便,在最高位进位时会方便很多。
接着将高精度加法封装成一个函数
这里的 auto 的意思是 编译器会自动 推断 变量的类型。
最后输出我们的数组C,由于最开始我们是倒着存的,所以我们需要倒着输出。
接着来看add函数
返回类型为 vector< int > 数组,函数参数为两个vector< int > 类型。
首先定义一个 vector< int > 作为结果, 最后会将该容器返回。
在刚才的思路中,我们模拟了人类加法的过程,由于在加法的过程中 会有进位,所以需要创建一个变量来存储进制。
这里的 t 的含义是 是上一位所进的位,由于个位 是最低位,所以刚开始的进位为0。
接下来就需要遍历两个数组中的每一位的数字。
这里需要关注的是循环的判断条件,意思是 下标 i 不能跑到 两个数组的大小中 较大的那一个的 外边。
接着将 t 加上 该位的值。
这里不能直接加上 下标 i 的值,需要判断一下 下标 i 有没有值,比如下面这个例子。
当 下标 i 走到这个地方的时候 ,此时 下面没有值,所以就不能加。
加完了之后,此时有两种情况,第一种是 t > 10,则需要进一位,然后插入 t % 10 ;第二种是 t < 10,则直接插入t。
对于这两种情况,我们不需要分类,不需要写if 语句,只需要直接插入 t % 10.
因为如果小于10的话 % 10 还是 不变的。
插入之后,由于 我们最初定义 t 的 含义为 上一位数的 进位,所以 最后需要 t /= 10。
如果t >= 10 那么 t 就会等于 1,t < 10那么就会等于0,那么到下一次 i 的时候就会加上上一次的进位。
写到这看似写完实则还差一步,我们来看下面这个例子。
这里我们模拟了倒着存放,其中根据for循环 i下标 最多循环到 9 这个位置,但是我们发现,最后还需要再进一位,所以 就需要 在最后 加上 t 这个进位。
当然前提得不是0,要不然结果最后开头会有个0.
最后返回我们的vector容器C即可。
可以做出的优化
add函数的参数换成引用
如果不使用引用的话,那么就会重新开辟一份空间,因为形参是实参的一份临时拷贝。
而由于引用是 别名,也就是操作的是原vector容器,所以就不会浪费额外的空间,当然算法题其实也没那么需要注意空间,只需要小于题目要求即可,但是还是引用好一点。
让函数 当中 的A容器的大小一定比 B的大
所以我们可以加上这条语句。
如果 B 数字比较长,那么就反着放调用,因为是加法,所以也不影响结果。
这样就保证了 我的 A一定 比 B 的长度要大,所以,下面的语句也可以进行修改。
t 放到循环的 判断条件上
这里最后的一条语句也可以换成下面的。
此时就算 i 下标不满足, t 如果不为0,也就是如果有进位的话,也会执行,for循环。
不过这里会加上 一个 if 判断,如果不加的话,会越界,因为 此时 i 已经不满足条件了。
所以这个优化也不能算优化,看个人喜好决定怎么书写。
完整代码:
#include <iostream>
using namespace std;
#include <vector>
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(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;
}
下面为不用 vector的代码
#include <iostream>
#include <string>
using namespace std;
const int N = 1e5+10;
int A[N], B[N], C[N], asz, bsz, csz;
string a, b;
void add(int A[], int& asz, int B[], int& bsz, int C[], int& csz)
{
for (int i = 0, t = 0; i < asz || i < bsz || t; i++)
{
if (i < asz) t += A[i];
if (i < bsz) t += B[i];
C[csz++] = t % 10;
t /= 10;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> a >> b;
for (int i = a.size()-1; i >= 0; i--) A[asz++] = a[i] - '0';
for (int i = b.size()-1; i >= 0; i--) B[bsz++] = b[i] - '0';
add(A, asz, B, bsz, C, csz);
for (int i = csz-1; i >= 0; i--) cout << C[i];
return 0;
}
完