高精度的整体思路:
为什么一个数据会存在最大数?我们知道,一个数字会转化成二进制存储在内存中。而每个二进制位都会消耗一个比特位。我们以int 为例,其大小是4个字节,32个比特位。因此,其所表示的最大数即32个比特位全是1的时候。
因此,我们只要打破内存的限制,就能实现超级大的数字之间的加减乘除运算。那么如何打破呢?此时我们就需要用到我们学过的数组,我们的数组可以在相应的内存区域限制内不断地开辟,从而满足我们的需要。
==因此高精度的本质就是利用数组模拟各种运算法则,从而得到结果。==
一、加法
1、思路:
我们以上述图示为例子,我们创建两个数组,模拟两个数字的位数,从个位开始运算。
我们创建一个中间变量t来存储每一位两个数字加起来的结果。但是我们需要注意的是,结果中的每一位不仅来自A,B两个数字中对应位数的相加,还包括前一位的进位。
个位的加减是没有前一位的进位的,因此我们初始化 t 为0。然后运算结果如上图所示。我们将t%10后,就是该位所应保留的数字,然后将t在/=10,此时t就保留了进到下一位中的进位。
因此,我们这里要写成:t += A[i] + B[i]
。一定是+=
!!。否则就会丢掉进位。不懂得话,可以详细看上面图片中的手写例子。
但是我们还需要注意的一点就是,当我们算到最后一位的时候,最后一位计算结束的时候,我们的t有可能依然有进位。由于A,B已经没有下一位了。所以如果不特殊处理以下的话,这一位就丢掉了。因此我们用if语句判断一下,如果存有进位,则再开一位存储1。
另外的一些细节,我们看完模板再解释。
2、模板:
(1)C++版:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<int>add(vector<int>&A,vector<int>&B)
{
int t=0;
vector<int>C;
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!=0)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');
//调用加法函数
vector<int>C=add(A,B);
//倒序输出结果
for(int i=C.size()-1;i>=0;i--)printf("%d",C[i]);
return 0;
}
(2)C语言版:
#include<stdio.h>
#include<string.h>
char a[100005];
char b[100005];
int A[100005];
int B[100005];
int C[100005];
int main()
{
scanf("%s",a);
scanf("%s",b);
int lena = strlen(a);
int lenb = strlen(b);
//逆序数组
for (int i = 0; i < lena;i++)
{
A[lena - i - 1] = a[i] - '0';
}
for (int i = 0; i < lenb;i++)
{
B[lenb - i - 1] = b[i] - '0';
}
//判断结果的最大位数
int lenc = (lena > lenb ? lena : lenb)+1;
//开始加法
int t=0;
int i;
for (i = 0; i < lenc;i++)
{
t+=A[i]+B[i];
C[i]=t%10;
t/=10;
}
if(t!=0)C[i]=1;
//删除前导零,避免出现:000012的情况。但是要注意0这种特殊情况
while(C[lenc]==0&&lenc>0)
{
lenc--;
}
for (int i = lenc; i >= 0;i--)
{
printf("%d",C[i]);
}
return 0;
}
我们这里解释一下为什么要倒置数组,因为我们输入一个字符串后,第一个元素是最高位。但是我们上述图片举得例子中,第一个元素是个位,所以我们需要倒置数组,不要忘记剪掉:'0'