是什么?
由于int和long long能够存储的数字范围太小,当我们想要实现至少几千位的数字相乘时,就不能直接设两个变量相乘,而是需要用到高精度算法。
高精度算法是通过将数字的每一位数都分开存进一个数组,把一个几千位的数字用数组表示出来。例如,数字2022就可以通过一个数组a = {2, 2, 0, 2}来存(通常倒着存数组,方便模拟)。接着,通过模拟加减乘除的运算过程,如进位,借位等就可以进行高精度计算。
代码实现及原理
加法
因为是倒着存数字,即个位存在a[1],十位存在a[2]等等,所以就可以从数组开头往后模拟。将对应位数字相加,再加上上一位数字的进位,再检查是否需要进位,最后得出在这一位上的结果,全程跟人计算的过程相似。
int a[1001], b[1001], ans[1010]//两个相加的数字和它们的和
int l;//记录位数更多的数字的位数
void add(){
int x = 0;//记录进位
for(int i = 1;i <= l;i++){
ans[i] = a[i] + b[i] + x;//数位相加
x = ans[i]/10;//计算进位
ans[i] %= 10;//减掉进位
if(x > 0 && i>= l){//如果需要进位到最高位的下一位,就增加位数
l++;
ans[i+1] = x;
}
}
}
减法
跟加法相似,唯一的不同就是将进位,替换成借位:
//a[i]被减数,b[i]减数,被减速一定要比减数大!,l代表被减数的长度
void mi(){
for(int i = 1;i <= l;i++){
if(a[i] >= b[i]){
ans[i] = a[i] - b[i];//不需要借位
}
else{
a[i+1]-=1;
ans[i] = a[i] - b[i] + 10;//需要借位
}
}
}
乘法
模拟人做乘法,乘数每一位与另外一个乘数的每一位都要相乘,所以需要用到嵌套for循环,并且和加法一样也要考虑到进位。
//a[] b[]是两个乘数,l1和l2是分别两个乘数的位数
void mul(){
for(int i = 1;i<=l1;i++){
x = 0;
for(int j = 1;j <= l2;j++){
ans[i+j-1] += a[j]*b[i] + x;//每个位数都相乘
x = ans[j+i-1] / 10;//计算进位
ans[j+i-1] = ans[j+i-1] % 10;
if( x>0 && j == l2 ) ans[j+i] = x;//如果后面没有数了但需要进位,就直接等于x
}
}
}
除法
通过使被除数的每一位都减去除数,直到不够减了为止,算出商(被除数一定要比除数打,且能被整除):
int a[], b[], c[], ans[], la, lb, lc;//数组及其位数
int compare(int a[], int b[]){//比较a,b数组的大小
if(la > lb) return 1;//先比较各自的位数
if(la < lb) return -1;
for(int i = la;i>0;i--){//若位数相同,就从最高位逐位比较
if(a[i] > b[i]) return 1;
if(a[i] < b[i]) return -1;
}
return 0;//两个数相同
}
int lp, lq;
void numcpy(int p[], int q[], int det){//复制p数组到q数组从det开始的地方
for(int i = 1;i<=p[0];i++{
q[i+det-1] = p[i];
}
lq = lp + det - 1;//位数也要更新
}
void jian(int a[], int b[]){//a = a-b
int flag;
flag = compare(a, b);
if(flag == 0){
la = 0;
return;
}
if(flag == 1){
for(int i = 1;i<=la;i++){
if(a[i] < b[i]){
a[i+1]--;
a[i]+=10;
}
a[i] = a[i] - b[i];
}
}
while(la>0 && a[la] == 0) la--;
return;
}
int tmp[];
void divide(int a[], int b[], int c[]){//除法
lc = la - lb + 1;//暂时计算位数
for(int i = lc;i>0;i--){//通过减法来模拟除法
numcpy(b, tmp, i);
while(compare(a, tmp)>+0){
c[i]++;
jian(a,tmp);
}
}
while(lc>0 && c[lc] == 0) lc--;
return;
}