高精度加法
呐!众所周知,数据是有范围的
\(Python \&\& Java:\) sorry,高精度真的可以为所欲为
本文为博客园 ShyButHandsome的原创作品,转载请注明出处
注:右边有目录,方便快速浏览
需求原因
C++
中的数据类型是有范围的
实现思路
虽然内置数据类型范围不大
但是字符串能很长啊!
我们将加数的每一位都看作是一个字符的话
那我们就得到了两个字符串
代码实现
解释都在代码里了
#include <iostream>
// EXIT_SUCCESS在stdlib库中
#include <cstdlib>
// strlen函数需要cstring库
#include <cstring>
using namespace std;
// 500+6防止数组越界
const int LENGTH_LIMIT = 5e2 + 6;
// char表示的整数 减去一个‘0’就可以得到响应整数的ascii
const int INT_CHANGER = '0';
// 个位数不能超过10
const int SINGLE_LIMIT = 10;
char stringA[LENGTH_LIMIT];
char stringB[LENGTH_LIMIT];
int invertedA[LENGTH_LIMIT];
int invertedB[LENGTH_LIMIT];
int sum[LENGTH_LIMIT];
int main(void)
{
cin >> stringA >> stringB;
// 倒序储存
int lengthA = strlen(stringA);
for (int i = 0; i < lengthA; i++)
{
// 由于strlen返回的长度是符合正常思维(从1开始)
// 但我们是从0开始,所以要额外 - 1
invertedA[i] = stringA[lengthA - i - 1] - INT_CHANGER;
}
int lenghtB = strlen(stringB);
for (int i = 0; i < lenghtB; i++)
{
invertedB[i] = stringB[lenghtB - i - 1] - INT_CHANGER;
}
// 和的最大长度是a,b最大值+1
const int MAX_LENGTH = ((lengthA < lenghtB) ? lenghtB : lengthA) + 1;
// 进位
int carry = 0;
// 模拟计算
for (int i = 0; i < MAX_LENGTH; i++)
{
// 对应位相加
sum[i] = invertedA[i] + invertedB[i] + carry;
// 记录下进位
carry = sum[i] / SINGLE_LIMIT;
// 进位操作
sum[i] %= SINGLE_LIMIT;
}
// 这里length选择放在循环外,因为两个循环都会用到它
// +1是因为strlen返回的数组长度是从1开始计数的
int length = MAX_LENGTH;
// 删除前导零(确定数字实际长度)
// 这里取length>0,因为
// 如果删到最后一位就必须得保留,不管它是不是0
for (length; length > 0; length--)
{
if (sum[length] == 0)
{
// 接着处理下一位
continue;
}
else
{
// 如果遇到一位非零就说明前导零删干净了
// 接着删就会删去数字中的0了
break;
}
}
// 正序输出
for (length; length >= 0; length--)
{
cout << sum[length];
}
// 额外输出一个换行
cout << endl;
// EXIT_SUCCESS means 0
return EXIT_SUCCESS;
}
再给出一份用STL写的:
#include <bits/stdc++.h>
using namespace std;
int main(void)
{
string strA, strB;
cin >> strA >> strB;
vector<int> numA, numB, sum;
for (int i = strA.size() - 1; i >= 0; i--)
{
numA.push_back(strA[i] - '0');
}
for (int i = strB.size() - 1; i >= 0; i--)
{
numB.push_back(strB[i] - '0');
}
int carry = 0;
for (int i = 0; i < (max(numA.size(), numB.size())); i++)
{
sum.push_back(carry);
// If lenA != lenB
sum[i] += (i > (numA.size() - 1) ? 0 : numA[i]) + (i > (numB.size() - 1) ? 0 : numB[i]);
carry = (sum[i]) / 10;
sum[i] %= 10;
}
if (carry != 0)
{
cout << carry;
}
for (int i = sum.size() - 1; i >= 0; i--)
{
cout << sum[i];
}
cout << endl;
return 0;
}
易错点
下面是我总结出的几个易错点
每个易错点都给出了测试数据
可以利用右上角的复制按钮快速复制
没有处理进位
包括
- 每次没有计算上次的进位啊
- 每次没有加上上次的进位啊
- 边界没有进位啊
- 等等
测试数据:
输入:
56546876443156448001
56453168410002134684
输出:
113000044853158582685
删除前导零错误
测试数据:
输入 1:
11111111111111111111111111
9999999999999999999999999999999999
输出 1:
10000000011111111111111111111111110
输入 2:
0
0
输出 2:
0
STL还要注意长度不一样
输入:
350204156568812004512541458715942878921069349854678
5120132301230048014584016540526804565814706519846494321001345794503242112976563432120
输出:
5120132301230048014584016540526804916018863088658498833542804510446121034045913286798