大数运算-加法(C/C++实现)

大数运算-加法

前言

  • 在很多情况下,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
  • 我们通过某种方式将其存入了数组中,从左往右观察上面这个表格,虽然我们想计算的是987654321 + 56789,但是存入数组中后我们发现,现在已经无法分辨 a 和 b 的值了。
    • 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[n] = a[n] + b[n] + c[n], 如果结果大于等于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[]),每一位分别是0987711110,如果忽略前置0,结果就是98771110,这便是987654321 + 56789的结果。
  • 以上就是大数加法的基本步骤了,实际上,我们并不需要数组 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[n] = a[n] + b[n],再根据结果决定是否需要进位。
    • 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
  • 结果同样是987711110


    代码实现

    1. 首先是如何逆序将数据存入数组,我们可以在输入数据的时候将 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
#include
#include
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()函数中的一些边界值即可。

你可能感兴趣的:(大数运算)