第三十三天:高精度运算
高精度运算:加法与乘法的C++ 实现全解析
在编程领域,处理超出常规数据类型表示范围的数值运算是一项常见且具有挑战性的任务。高精度加法和高精度乘法是其中的典型问题,下面我们将分别针对这两个问题,从问题要求、完整代码到方式方法进行详细讲解。
高精度加法
问题要求
- 题目描述:计算两个不超过200位的非负整数的和。
- 输入:输入有两行,每行是一个不超过200位的非负整数,可能存在多余的前导0。
- 输出:输出为一行,即两个输入整数相加后的结果,且结果不能有多余的前导0。
完整代码
#include <iostream>
#include <string>
#include <algorithm>using namespace std;string addStrings(string num1, string num2) {string result;int carry = 0;int i = num1.size() - 1;int j = num2.size() - 1;while (i >= 0 || j >= 0 || carry!= 0) {int sum = carry;if (i >= 0) {sum += num1[i] - '0';i--;}if (j >= 0) {sum += num2[j] - '0';j--;}result.push_back(sum % 10 + '0');carry = sum / 10;}reverse(result.begin(), result.end());while (result.size() > 1 && result[0] == '0') {result.erase(result.begin());}return result;
}int main() {string num1, num2;cin >> num1 >> num2;cout << addStrings(num1, num2) << endl;return 0;
}
方式方法讲解
- 字符串存储大整数:
- 由于要处理的整数位数多达200位,远远超出常规数值类型(如
int
、long long
)的表示范围,所以采用string
类型来存储大整数。string
类型能够方便地处理长度可变的字符序列,每个字符对应大整数的一位数字。例如,字符串"123"
表示整数123 ,在代码中,num1
和num2
就是用于存储输入的两个大整数的字符串。
- 由于要处理的整数位数多达200位,远远超出常规数值类型(如
- 字符与数字的转换:
- 在进行加法运算时,需要将字符串中的字符转换为实际的数字。通过字符减去字符
'0'
来实现,例如,字符'5'
减去'0'
得到整数5 。代码中num1[i] - '0'
和num2[j] - '0'
就是这种转换操作,将字符串中的字符形式的数字转换为数值,以便进行加法运算。
- 在进行加法运算时,需要将字符串中的字符转换为实际的数字。通过字符减去字符
- 模拟竖式加法:
- 逐位相加:模拟手动竖式加法过程,从两个数的最低位开始逐位相加。通过
while
循环实现,i
和j
分别初始化为num1
和num2
的最后一位(最低位)的索引。只要num1
还有未处理的位(i >= 0
),或者num2
还有未处理的位(j >= 0
),或者有进位(carry!= 0
),循环就会继续。每次循环处理一位数字的加法。 - 进位处理:使用变量
carry
来保存进位。在每一位相加时,先将carry
加到当前位的和sum
中。例如,如果当前位相加结果为13,sum
就是13 ,carry
则更新为1(13除以10的商),当前位结果为3(13对10取模)。代码中carry = sum / 10
用于更新进位,result.push_back(sum % 10 + '0')
用于将当前位结果(转换为字符)添加到结果字符串result
中。
- 逐位相加:模拟手动竖式加法过程,从两个数的最低位开始逐位相加。通过
- 结果处理:
- 反转结果字符串:在逐位相加的过程中,结果是从低位到高位依次生成并存储在
result
字符串中的,所以需要将其反转才能得到正确的数字顺序。通过调用<algorithm>
头文件中的reverse
函数来实现,reverse(result.begin(), result.end())
将result
字符串中的字符顺序反转。 - 去除前导0:为满足输出要求,结果不能有多余的前导0。通过一个
while
循环来实现,只要result
的长度大于1且第一个字符是0
,就删除第一个字符,while (result.size() > 1 && result[0] == '0') { result.erase(result.begin()); }
,直到result
满足没有多余前导0的条件。
- 反转结果字符串:在逐位相加的过程中,结果是从低位到高位依次生成并存储在
高精度乘法
问题要求
- 题目描述:输入两个高精度正整数
M
和N
(M
和N
均小于100位),求这两个高精度数的积。 - 输入:输入两个高精度正整数
M
和N
。 - 输出:输出这两个高精度数的积。
完整代码
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>using namespace std;string multiplyStrings(string num1, string num2) {if (num1 == "0" || num2 == "0") return "0";vector<int> product(num1.size() + num2.size(), 0);for (int i = num1.size() - 1; i >= 0; i--) {for (int j = num2.size() - 1; j >= 0; j--) {int mul = (num1[i] - '0') * (num2[j] - '0');int sum = mul + product[i + j + 1];product[i + j + 1] = sum % 10;product[i + j] += sum / 10;}}string result;for (int i = 0; i < product.size(); i++) {if (i == 0 && product[i] == 0) continue;result.push_back(product[i] + '0');}return result;
}int main() {string num1, num2;cin >> num1 >> num2;cout << multiplyStrings(num1, num2) << endl;return 0;
}
方式方法讲解
- 字符串存储与数字转换:
- 同样使用
string
类型存储大整数,利用num1[i] - '0'
和num2[j] - '0'
将字符串中的字符转换为数字,为乘法运算做准备,与高精度加法类似。
- 同样使用
- 模拟竖式乘法:
- 逐位相乘与累加:通过两层嵌套的
for
循环模拟竖式乘法过程。外层for
循环遍历num1
的每一位,内层for
循环遍历num2
的每一位。对于num1
的第i
位与num2
的第j
位,计算它们的乘积mul = (num1[i] - '0') * (num2[j] - '0')
,然后将这个乘积与product
数组中对应位置的数值相加,即int sum = mul + product[i + j + 1]
。这模拟了手动竖式乘法中每一位相乘并对应相加的操作。 - 进位处理:在累加过程中,如果某一位置的和大于等于10,需要处理进位。将和对10取模,得到的余数作为当前位的值存入
product
数组,即product[i + j + 1] = sum % 10
;将和除以10的商作为进位加到前一位,即product[i + j] += sum / 10
。
- 逐位相乘与累加:通过两层嵌套的
- 使用
vector
存储中间结果:- 创建一个
vector<int>
类型的product
数组,长度为num1.size() + num2.size()
,用于存储逐位相乘的中间结果。vector
具有动态调整大小和高效访问元素的特点,方便在计算过程中对结果进行操作。
- 创建一个
- 结果处理与转换为字符串:
- 计算完成后,将
vector
中的结果转换为字符串形式。首先跳过前导0(如果有),即if (i == 0 && product[i] == 0) continue;
,然后将每一位数字转换为字符并添加到结果字符串result
中,result.push_back(product[i] + '0');
,最终返回处理好的结果字符串。
- 计算完成后,将