a + b 自然是个很简单的问题,但若 a 和 b 都能达到两百位的话,连 unsigned long long 都存不了,这是就要用到高精度加法。
具体原理就是让电脑模拟列竖式加法。
首先我们用数组存这两个数。为了方便读入,我们采用字符串读入,然后将其转化成数字存进数组中。存进数组的时候要倒着存入,为什么呢?这样的话就能保证两个数的每一位都对齐了,为接下来的模拟列竖式提供了很大的便利。
模拟列竖式其实也不必多说,写法也不少。其实关键在于进位的问题,一种写法是先进位,在把这一位的两数相加;一种是先相加,然后为下一位进位。这两种写法是一样的,喜欢哪一种,就看个人习惯吧。
那么先说一下第一种方法。
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int maxn = 1e5 + 5; char a1[maxn], b1[maxn]; int a[maxn], b[maxn], c[maxn]; int jinwei = 0; int main() { scanf("%s%s", a1, b1); int la = strlen(a1), lb = strlen(b1); for(int i = 0; i < la; ++i) a[la - 1 - i] = a1[i] - '0'; //倒着存入 for(int i = 0; i < lb; ++i) b[lb - 1 - i] = b1[i] - '0'; for(int i = 0; i < max(la, lb); ++i) //当然要加到位数多的数了 { c[i] = c[i] + jinwei + a[i] + b[i]; jinwei = c[i] / 10; c[i] %= 10; } int x = max(la, lb); if(jinwei > 0) c[x] += jinwei; //处理最高位的进位 while(x > 0 && c[x] == 0) x--; //删除前导0,比如 0000 + 00 = 0,而不是 0000 for(int i = x; i >= 0; --i) printf("%d", c[i]); //倒着输出 printf(" "); return 0; }
仔细瞅一瞅,这个代码其实还可以优化一下:
1.不用开 c 数组,在 a 数组上改动即可。
2.这其实不算什么优化,只不过代码看得更简洁:考虑一下最高位进位的问题,若最高位可以进位,那新的一位一定是超出了 max(la, lb),因此会跳出循环,所以我们的写法就是在循环外面单独处理。但其实我们完全可以把它放到循环里面,只要把最高位的下一位看成一位,而且可以确定的是,这一位一定不会再进位了(因为没有数,默认是0,加任何小于10的数都不会进位),这么一改,我们也就不用考虑最高位进位的事了。
发一下优化后的
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 const int maxn = 1e5 + 5; 8 char a1[maxn], b1[maxn]; 9 int a[maxn], b[maxn]; 10 int jinwei = 0; 11 int main() 12 { 13 scanf("%s%s", a1, b1); 14 int la = strlen(a1), lb = strlen(b1); 15 for(int i = 0; i < la; ++i) a[la - 1 - i] = a1[i] - '0'; 16 for(int i = 0; i < lb; ++i) b[lb - 1 - i] = b1[i] - '0'; 17 for(int i = 0; i <= max(la, lb); ++i) //注意加了个 '=',默认加到最高位的下一位 18 { 19 a[i] = a[i] +jinwei + b[i]; 20 jinwei = a[i] / 10; 21 a[i] %= 10; 22 } 23 int x = max(la, lb); //不用考虑最高位进位的事了 24 while(x > 0 && a[x] == 0) x--; //删除前导0 25 for(int i = x; i >= 0; --i) printf("%d", a[i]); 26 printf(" "); 27 return 0; 28 }
那就顺便说一下第二种方法吧。
其实差不多,只不过不用开一个变量记录进位了,因为每一次考虑的是给下一位进位,只要 c[i + 1] 处理一下就行了,除此之外,也就没什么差别。
就直接发优化后的代码了
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 const int maxn = 1e5 + 5; 8 char a1[maxn], b1[maxn]; 9 int a[maxn], b[maxn]; 10 int main() 11 { 12 scanf("%s%s", a1, b1); 13 int la = strlen(a1), lb = strlen(b1); 14 for(int i = 0; i < la; ++i) a[la - 1 - i] = a1[i] - '0'; 15 for(int i = 0; i < lb; ++i) b[lb - 1 - i] = b1[i] - '0'; 16 for(int i = 0; i <= max(la, lb); ++i) 17 { 18 a[i] += b[i]; 19 a[i + 1] += a[i] / 10; //进位 20 a[i] %= 10; 21 } 22 int x = max(la, lb); 23 while(x > 0 && a[x] == 0) x--; 24 for(int i = x; i >= 0; --i) printf("%d", a[i]); 25 printf(" "); 26 return 0; 27 }
总结一下,高进度只不过是一个模拟,只要耐心仔细一点,把进位搞明白,就没什么不好写的了。