大数运算-加法(C/C++实现)
2017-07-22 01:07
603 查看
大数运算-加法
前言
在很多情况下,c/c++所提供的基本数据类型已经不能满足我们的需求了,所以我们需要一种方法来解决一些大数的运算,在小学进行加法运算的时候,无论数据是什么,有多少位,都通通采取列竖式的方法进行计算并得出结果,本文将使用数组模拟列竖式计算来解决大数的加法运算。问题分析
首先我们先给定一组数据,来辅助说明整个计算过程a = 987654321
b = 56789
计算 a + b 的结果
将两个数字的每一位分别存入两个数组:因为所给定的数据不是很大,这里就开辟长度为10的数组进行说明,a数组(a[])用来存储数字a的每一位,b数组(b[])用来存储数字b的每一位,c数组(c[])用来存储计算的结果(在程序中开辟一个新的数组,数组的每一位都是随机数,所以需要将数组初始化,把数组的每一位都赋值为0)。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
a[] | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
b[] | 5 | 6 | 7 | 8 | 9 | 0 | 0 | 0 | 0 | 0 |
c[] | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
a 的值变成了9876543210?
b 的值变成了5678900000?
我们可以记录下数字 a 最后一位所在数组的位置,数字 b 最后一位所在数组的位置,这样虽然不会出现上面的问题了,但是在实际的计算过程中会很繁琐,并伴随着各种问题。接下来,我们换一种思路来将数字存入数组(逆序存入),存入的结果如下表所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
a[] | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
b[] | 9 | 8 | 7 | 6 | 5 | 0 | 0 | 0 | 0 | 0 |
c[] | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
a = 0987654321 = 987654321
b = 0000056789 = 56789
这样的结果才是我们所需要的,接下来我们继续来模仿列竖式的方法进行计算,c
= a
+ b
+ c
, 如果结果大于等于10,我们就向前进一位。
c[0] = a[0] + b[0] + c[0] = 1 + 9 + 0 = 10,结果等于10, 向前进一位,进位之后c[1] = 1,c[0] = 0;
c[1] = a[1] + b[1] + c[1] = 2 + 8 + 1 = 11,结果大于10,向前进一位,进位之后c[2] = 1, c[1] = 1;
c[2] = a[2] + b[2] + c[2] = 3 + 7 + 1 = 11,结果大于10,向前进一位,进位之后c[3] = 1, c[2] = 1;
重复这样的操作,直到数组的最后一个元素。
执行完上述操作后,表格变成如下所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
a[] | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
b[] | 9 | 8 | 7 | 6 | 5 | 0 | 0 | 0 | 0 | 0 |
c[] | 0 | 1 | 1 | 1 | 1 | 7 | 7 | 8 | 9 | 0 |
以上就是大数加法的基本步骤了,实际上,我们并不需要数组 c 进行辅助运算,前文中使用原因只是为了方便说明,如果不利用c数组,那么初始的表将会变成如下样子:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
a[] | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
b[] | 9 | 8 | 7 | 6 | 5 | 0 | 0 | 0 | 0 | 0 |
= a
+ b
,再根据结果决定是否需要进位。
b[0] = a[0] + b[0] = 1 + 9 = 10,结果等于10,向前进一位,进位之后b[1] = 9, b[0] = 0;
b[1] = a[1] + b[1] = 2 + 9 = 11,结果大于10,向前进一位,进位之后b[2] = 8, b[1] = 1;
b[2] = a[2] + b[2] = 3 + 8 = 11,结果大于10,向前进一位,进位之后b[3] = 7, b[2] = 1;
重复这样的操作,直到数组的最后一个元素。
执行完上述操作后,我们可以得到这样一个表:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
a[] | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
b[] | 0 | 1 | 1 | 1 | 1 | 7 | 7 | 8 | 9 | 0 |
代码实现
首先是如何逆序将数据存入数组,我们可以在输入数据的时候将 a 和 b 分别存入两个字符串,然后获取字符串的长度,从字符串的最后一个元素开始依次添加到数组中,添加的时候只需要把字符减去字符0。//这里str1是字符串,a是数组 //逆序存入str1中的元素到a数组 for(int i = strlen(str1) - 1, j = 0; i >= 0; i--) a[j++] = str1[i] - '0'; //这里str2是字符串,b是数组 //逆序存入str2中的元素到b数组 for(int i = strlen(str2) - 1, j = 0; i >= 0; i--) b[j++] = str2[i] - '0'; //执行完这两个循环之后就完成了逆序存入的操作
2.相加和进位:两个数组的每一位都分别相加,再通过相加的结果判断是否需要进位,maxn为数组的长度,但是这样的话,会有很多没用意义的计算,就比如上文中的例子,a[9] + b[9]就是没有意义的,后面会说到这个该如何优化。
//这里的maxn是数组的长度 for(int i = 0; i < maxn; i++) { b[i] += a[i]; if(b[i] >= 10) { b[i + 1] += b[i] / 10; b[i] %= 10; } }
3.结果的输出:因为输出的时候需要从数组的最后一位向前输出,也就是说会有很多前置的零,上文中的例子,如果直接输出的话结果就是0987711110,但是我们并不需要前置0,所以在输出结果的时候应该过滤掉前置0,也就是说在输出的时候从第一个不为0的位置开始输出,实现这个的方式有很多,我是用以下的方式实现的输出:
//这里的maxn同上 int i; //注意:这个for循环有一个分号 for(i = maxn - 1; i >= 0 && b[i] == 0; i--); if(i >= 0) for( ; i >= 0; i--) cout << b[i]; else cout << 0; cout << endl;
下面是完整的代码:
#include<iostream> #include<cstring> #include<cstdlib> using namespace std; const int maxn = 1000; char str1[maxn], str2[maxn]; int a[maxn], b[maxn]; void sum() { //逆序存入 for(int i = strlen(str1) - 1, j = 0; i >= 0; i--) a[j++] = str1[i] - '0'; for(int i = strlen(str2) - 1, j = 0; i >= 0; i--) b[j++] = str2[i] - '0'; //相加和进位 for(int i = 0; i < maxn; i++) { b[i] += a[i]; //进位操作 if(b[i] >= 10) { b[i + 1] += b[i] / 10; b[i] %= 10; } } //输出结果 int i; //过滤掉前置0 for(i = maxn - 1; i >= 0 && b[i] == 0; i--); if(i >= 0) for( ; i >= 0; i--) cout << b[i]; //如果保存结果的数组中全部为0,上面的操作会过滤掉所有的0,不会有输出,所以这里输出一个0 else cout << 0; cout << endl; } int main() { //清空数组和字符数组 memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); memset(str1, 0, sizeof(str1)); memset(str2, 0, sizeof(str2)); //输入 cin >> str1 >> str2; //执行加法计算 sum(); system("pause"); return 0; }
关于maxn
maxn是在程序中定义的一个常量,但是在计算的过程中如果直接使用,会运行很多没有意义的计算过程,我们可以这样做一个优化,定义一个变量MAX,令MAX的值等于最长的字符串长度 + 1,即:MAX = max(strlen(str1), strlen(str2)) + 1;
加1的原因:n位+n位的结果可能会是n+1位,举个例子来说,如果计算999+111,实际的结果应该是1110,如果不加1,那么输出的结果就是110。
用MAX替换sum()函数中的一些边界值即可。
相关文章推荐
- 多项式的加法和乘法算术运算的C++实现
- C++ std::list实现大整数加法运算
- 使用C++的string实现高精度加法运算的实例代码
- 用C++实现高精度加法运算
- 使用C++的string实现高精度加法运算
- 使用C++的string实现高精度加法运算
- C++实现大数运算 加法部分。
- c++实现链式存储结构实现一元多项式的加法运算
- 复数乘法运算(三次实数乘法)-c++代码实现及运行实例结果
- DCT变换及量化的c++实现(基于opencv矩阵运算)
- 在C/C++代码中使用SSE等指令集的指令(5)SSE进行加法运算简单的性能测试
- Leetcode#371. Sum of Two Integers (位运算实现加法)
- C/C++中移位实现乘除法运算
- 大数运算之加法和乘法算法C++模板
- 用C++实现时间的加减运算
- C++ 02-线性结构2 一元多项式的乘法与加法运算
- 位运算实现加法
- 位运算实现加法运算
- 利用位运算实现两个整数的加法运算(加注释)
- Python位运算实现加法和乘法