C++的高精度加法

为什么需要高精度计算

对于 C++ 而言,最大的数据为 long long64b8位),对于超过 8B 的数据,C++ 没有对应的数据类型进行表示。所以我们需要知道高精度计算。更详细的解释,可以参考这个网页https://blog.csdn.net/justidle/article/details/104414459

高精度加法计算原理

在读小学时,我们做加法都采用竖式方法,如图 1 所示。 这样,我们方便写出两个整数相加的算法。

我们就可以用 C++ 语言来模拟这个竖式加法的过程。我们可以考虑利用 C++ 的数组来存储对应数据,假设用数组 A 存储 856 的每一位,具体来说就是 A1 存储个位 6,A2 存储十位 5,A3存储百位 8;类似数组 A 的结构,使用数组 B 存储 255;类似数组 A 的结构,使用数组 C 来存储对应的和 1111。两数相加的结果就如图 2 所示。这样理论上来说,我们就可以计算无限大的数据。如上图 2 所示,下表表示对应的存储方式。

 数组 A数组 B数组 C
[0]651
[1]551
[2]821
[3]  1

总结:利用数组存储,突破存储的限制。每个位置存储 0 ~ 9 之间的数据。

高精度加法实现

思路

1、定义存储数组。

2、读入数据到数组中。注意是倒序存放,也就是个位放在数组下标为 0 的地方。

3、从个位开始模拟竖式加法的过程,完成整个加法。

4、删除前导 0 。所谓前导零,就是出现类似这样数据 01234,这个 0 实际是不需要的。

5、输出加法的结果。倒序输出加法的结果数组 C,因为我们的个位是存储在下标为 0 的地方。

技术细节说明

定义存储数组

根据题目的要求定义数组。这个部分代码如下:

const int MAXN = 1e5+4; //根据题目的最大值。+4为了防止A+B出现进位
char s1[MAXN] = {};//存储字符串
char s2[MAXN] = {};//存储字符串
int a[MAXN] = {};//存储加数A
int b[MAXN] = {};//存储加数B
int c[MAXN] = {};//存储和B

读入数据到数组

利用读入字符串的方法读入数据,再倒序写入到对应的数组中。这个部分代码如下:

    scanf("%s %s", s1, s2);//读入字符串A
    //将字符串写入到数组A中
    int len1 = strlen(s1);
    for (int i=0; i<len1; i++) {
        //倒序写入
        a[i] = s1[len1-i-1] - '0';
    }

    //将字符串写入到数组A中
    int len2 = strlen(s2);
    for (int i=0; i<len2; i++) {
        //倒序写入
        b[i] = s2[len2-i-1] - '0';
    }

注意:我们需要保存加数 A 和加数 B 的最大长度。因为竖式加法需要。

模拟竖式加法

有两个技术细节:1、进位如何保存;2、最高位进位如何解决。这个部分代码如下:

    //模拟竖式加法
    int jw=0;//进位
    int len = max(len1, len2)+1;//注意因为最高位可能出现进位
    for (int i=0; i<len; i++) {
        c[i] = a[i] + b[i] + jw;//当前加数A位数据+加数B位位数据+上一位的进位
        jw = c[i] / 10;//本次加法是否存在进位
        c[i] %= 10;//只能保存 0 ~ 9 的数据
    }

删除前导零

因为加法运算可能会出现最高位进位,所以我们在模拟竖式加法的时候多加了一位,所以我们需要判断是否需要删除前导零。这个部分代码如下:

    //删除前导零
    for (int i=len-1; i>=0; i--) {
        //因为我们是从索引 0 开始,所以最高位是保存在 len-1
        if (0==c[i] && len>1) {
            //注意要有 len>1 这个条件。考虑特殊情况,加法结果为 00,我们实际要输出 0。
            len--;
        } else {
            //第一个不是零的最高位,结束删除
            break;
        }
    }

输出计算结果

采用倒序的方式输出,因为我们数据保存是倒序结构,也就是低位在前。

    //逆序打印输出
    for (int i=len-1; i>=0; i--) {
        printf("%d", c[i]);
    }
    printf("\n");    

例题和 AC 代码

题目

题目链接

一本通 OJ:http://ybt.ssoier.cn:8088/problem_show.php?pid=1168

我自己 OJ:http://47.110.135.197/problem.php?id=1215

题目描述

求两个不超过 200 位的非负整数的和。

输入

有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。

输出

一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。

样例输入

22222222222222222222
33333333333333333333

样例输出

55555555555555555555

分析

题目告诉我们不超过 200 位,也就是 MAXN = 200+4。

AC 代码


#include <bits/stdc++.h>
using namespace std;

const int MAXN = 200+4; //根据题目的最大值。+4为了防止A+B出现进位
char s1[MAXN] = {};//存储字符串
char s2[MAXN] = {};//存储字符串
int a[MAXN] = {};//存储加数A
int b[MAXN] = {};//存储加数B
int c[MAXN] = {};//存储和B

int main() {
    scanf("%s %s", s1, s2);//读入字符串A
    //将字符串写入到数组A中
    int len1 = strlen(s1);
    for (int i=0; i<len1; i++) {
        //倒序写入
        a[i] = s1[len1-i-1] - '0';
    }

    //将字符串写入到数组A中
    int len2 = strlen(s2);
    for (int i=0; i<len2; i++) {
        //倒序写入
        b[i] = s2[len2-i-1] - '0';
    }

    //模拟竖式加法
    int jw=0;//进位
    int len = max(len1, len2)+1;//注意因为最高位可能出现进位
    for (int i=0; i<len; i++) {
        c[i] = a[i] + b[i] + jw;//当前加数A位数据+加数B位位数据+上一位的进位
        jw = c[i] / 10;//本次加法是否存在进位
        c[i] %= 10;//只能保存 0 ~ 9 的数据
    }

    //删除前导零
    for (int i=len-1; i>=0; i--) {
        //因为我们是从索引 0 开始,所以最高位是保存在 len-1
        if (0==c[i] && len>1) {
            //注意要有 len>1 这个条件。考虑特殊情况,加法结果为 00,我们实际要输出 0。
            len--;
        } else {
            //第一个不是零的最高位,结束删除
            break;
        }
    }

    //逆序打印输出
    for (int i=len-1; i>=0; i--) {
        printf("%d", c[i]);
    }
    printf("\n");    

    return 0;
}
<think>好的,我现在需要帮用户找到C++实现高精度加法的示例代码。用户提到了三个引用,我需要先仔细看看这些引用内容。 首先,引用[1]提供了一个C++高精度加法函数,使用vector来存储数字,并且按位相加处理进位。看起来这个函数可能处理的是逆序存储的数字,因为通常在处理高精度加法时,会从低位开始相加,所以可能需要将字符串反转存储到vector中。不过代码中没有显示输入处理的部分,用户可能需要自己处理字符串转换到vector的过程。 引用[2]提到高精度加法是用字符串输入的,并且步骤包括输入字符串、倒序存入数组、按位相加处理进位。这里可能涉及到将字符串转换为数字数组,并且可能需要倒序存储,方便从低位开始计算。但具体的代码示例没有给出,只有输入部分的伪代码。 引用[3]则提到用数组实现高精度加法,并附有源代码链接,但用户可能无法直接访问链接,所以需要根据已有的信息整合代码。 用户的需求是获取C++高精度加法示例代码。结合这三个引用,我需要综合出一个完整的示例,包括字符串输入、转换到数组或vector、相加处理进位,以及结果输出。 现在需要考虑如何将字符串转换为数字数组或vector。通常的做法是将字符串逆序存储,这样每一位对应数组的一个元素,比如字符串"123"转换为数组[3,2,1],这样在相加时可以从索引0开始处理每一位的加法。 然后,相加的过程需要处理进位,每一位相加后取模10得到当前位的值,除以10得到进位。循环处理每一位,直到所有位处理完毕,并且最后的进位不为零时需要添加到结果中。 引用[1]中的代码使用了vector<int>,并且在循环中处理两个数的相加,进位变量t在每次迭代中累加。这可能是一个正确的实现,但需要确认输入的两个vector是否已经逆序存储。例如,在函数add中,参数是vector<int>&a和b,可能假设它们已经是逆序存储的数字,每一位对应vector的一个元素。 因此,完整的代码应该包括: 1. 输入两个字符串s1和s2。 2. 将字符串转换为vector<int>,逆序存储每个字符对应的数字。 3. 调用add函数进行相加。 4. 处理结果vector,逆序输出得到最终的和。 现在需要补全这些步骤的代码。例如,将字符串转换为vector的部分,需要遍历字符串的每个字符,将其转换为int,并逆序存入vector。例如,字符串s1是"123",转换后的vector应该是[3,2,1]。 在引用[1]的代码中,主函数部分可能缺失,需要补充这部分。例如,读取输入字符串,转换到vector,调用add函数,然后处理结果。 可能的示例代码如下: 首先读取字符串s1和s2,然后将它们转换为vector<int>,逆序存储,每个字符减去'0'得到数字。然后调用add函数,得到的结果vector是逆序存储的,需要逆序输出。 需要注意处理前导零的情况,比如输入"000123"应该转换为321,但结果输出时需要去掉前面的零。不过在相加过程中,结果可能不会有前导零,除非结果为0,这时需要保留一个零。 另外,在引用[1]的代码中,循环条件是i < a.size() || i < b.size(),这会处理所有位,直到两个数都被处理完。进位t在循环结束后如果大于0会被添加到结果中。例如,如果最后还有进位,比如9+9=18,进位1会被加入结果。 现在,整合这些步骤写出完整的代码,并确保正确性。例如: #include <iostream> #include <string> #include <vector> using namespace std; vector<int> add(vector<int>& a, vector<int>& b) { vector<int> ret; int t = 0; 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]; ret.push_back(t % 10); t /= 10; } if (t) ret.push_back(t); return ret; } int main() { string s1, s2; cin >> s1 >> s2; vector<int> a, b; for (int i = s1.size() - 1; i >= 0; i--) a.push_back(s1[i] - '0'); for (int i = s2.size() - 1; i >= 0; i--) b.push_back(s2[i] - '0'); auto res = add(a, b); for (int i = res.size() - 1; i >= 0; i--) cout << res[i]; cout << endl; return 0; } 这样,代码就完成了输入字符串,转换到逆序vector,相加处理进位,最后逆序输出结果。这个应该符合用户的需求,并且参考了引用中的代码结构。 需要验证一下这个代码是否正确。例如,输入"123"和"456",转换为a=[3,2,1],b=[6,5,4],相加后得到每一位的和: i=0: 3+6=9, t=9%10=9, t=0 i=1: 2+5=7, t=7%10=7, t=0 i=2: 1+4=5, t=5%10=5, t=0 结果ret是[9,7,5],逆序输出579,正确。 如果输入"999"和"2",a=[9,9,9], b=[2]。相加时: i=0:9+2=11 → ret.push(1), t=1 i=1:9 → t=1+9=10 → push(0, t=1) i=2:9 → t=1+9=10 → push(0, t=1) 最后t=1 → push(1) ret=[1,0,0,1],逆序输出1001,即1001,正确。 所以这段代码应该可以正确处理进位的情况。 用户可能需要这个完整的示例,所以现在需要将代码整理出来,并解释关键步骤,比如字符串反转存储,按位相加处理进位,结果反转输出。同时需要注意代码的正确性和可读性。</think>以下是用C++实现高精度加法的完整代码示例及分步说明: ```cpp #include <iostream> #include <string> #include <vector> using namespace std; // 高精度加法核心算法 vector<int> add(vector<int>& a, vector<int>& b) { vector<int> result; int carry = 0; // 进位标志 for (int i = 0; i < a.size() || i < b.size(); ++i) { if (i < a.size()) carry += a[i]; // 取a的第i位 if (i < b.size()) carry += b[i]; // 取b的第i位 result.push_back(carry % 10); // 存储当前位计算结果 carry /= 10; // 计算进位值 } if (carry) result.push_back(carry); // 处理最高位进位 return result; } int main() { string num1, num2; cin >> num1 >> num2; // 将字符串逆序存储为数字数组(个位在前) vector<int> a, b; for (int i = num1.size()-1; i >= 0; --i) a.push_back(num1[i] - '0'); for (int i = num2.size()-1; i >= 0; --i) b.push_back(num2[i] - '0'); // 执行加法运算 auto sum = add(a, b); // 逆序输出结果(从最高位到个位) for (int i = sum.size()-1; i >= 0; --i) { cout << sum[i]; } return 0; } ``` ### 关键实现步骤说明 1. **输入处理**:通过字符串接收超长数字输入,避免数值溢出问题[^2] 2. **数据存储**:将字符串逆序转换为`vector<int>`,便于从个位开始计算 - 例如输入`"12345"`转换为`[5,4,3,2,1]` 3. **核心算法**: - 按位相加并处理进位,时间复杂度$O(n)$ - 使用`carry`变量同时记录当前位和与进位值 4. **结果输出**:将结果数组逆序输出,还原为正常数字顺序 ### 示例运行 输入: ``` 9999999999999999999 1 ``` 输出: ``` 10000000000000000000 ```
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值