高精度算法

高精度算法

1、高精度加法

描述:

求两个大正整数相加的和。

思路:

​ (1)用可变长数组vectorA,B存储

​ (2)将输入的大数用字符串a,b读入,并逆序存入A,B

​ (3)进行套用高精度模板

​ (4)最后逆序输出答案即可

代码模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <vector>
using namespace std;

const int N = 100010;

vector<int> A, B;
vector<int> Add(vector<int> A, vector<int> B)
{
vector<int> C;

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];
C.push_back(t % 10);
t /= 10;
}

if (t) C.push_back(1);
return C;
}

int main()
{
string a, b;
cin >> a >> b;

for (int i = a.size() - 1; i >= 0; i --) A.push_back(a[i] - '0');
for (int i = b.size() - 1; i >= 0; i --) B.push_back(b[i] - '0');

auto C = Add(A, B);

for (int i = C.size() - 1;i >= 0; i--) printf("%d", C[i]);

return 0;
}
注意:

最后可能会存在一位进位,需要特判,若存在直接push进答案最后即可

2、高精度减法

描述:

​ 求两个大正整数A,B的差。

思路:

高精度减法:大数A - 大数B
(1)用可变长数组vector存储A,B
(2)将字符串a、b逆序存入数组A、B中
(3)为了计算方便,我们再计算之前先保证较大的数减去较小的数,即我们要先判读出A、B谁大
(3.1)自定一个比较大小的cmp函数,用于返回若 A > B,返回true,反之返回false
(3.2)cmp函数的构造分为两种情况 位数相同 和 位数不同
(3.3)位数不同:肯定是位数长的数大
(3.4)位数相同,我们就需要从后向前遍历两个数组(因为我们已经逆序存储了),
找到第一个不相同的数进行比较,谁大,说明该数组表示的数大
(4)高精度减法的构造
(4.1)定义一个答案数组和临时变量t(存放借位)
(4.2)从前到后遍历较大数组(因为是逆序存储,所以原本低位相减变成了现在的前面的数相减):
(4.3)每一次遍历,先让较大的数减去借位,然后再减去较小的数中(需要判读较小的数是否还剩于)
(4.4)因为有可能相减为负数,这里利用一个技巧直接将(t + 10) % 10的结果加入答案末尾即可,这里保证了加入的一定是相减结果的绝对值
(4.5)更新借位,
如果t为负数,说明在相减的时候,借位了,让 t = 1,表示借了一位,保留到下一次计算进行减去
如果t为正数,说明在相减的时候,没有借位,让借位置零即可
(4.6)最后再进行去前导0即可
如果答案的长度大于1,且答案最后有0,就将0弹出即可
(5)最后逆序输出答案即可

代码模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <vector>
using namespace std;

bool cmp (vector<int> &A, vector<int> &B)
{
if (A.size() != B.size()) return A.size() > B.size();
else
{
for (int i = A.size() - 1; i >= 0; i --)
{
if (A[i] != B[i]) return A[i] > B[i];
}
}
return 1;
}

vector<int> sub(vector<int> A, vector<int> B)
{
vector<int> C;

int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t = A[i] - t;
if (i < B.size()) t -= B[i];
C.push_back((t + 10) % 10);
if (t < 0) t = 1;
else t = 0;
}

while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}

int main()
{
string a, b;
cin >> a >> b;

vector<int> A, B, C;

for (int i = a.size() - 1; i >= 0; i --) A.push_back(a[i] - '0');
for (int i = b.size() - 1; i >= 0; i --) B.push_back(b[i] - '0');

if (cmp(A, B)) C = sub(A, B);
else C = sub(B, A), cout << '-';

for (int i = C.size() - 1; i >= 0; i --) cout << C[i];

return 0;
}
注意:

​ (1)首先一定要保证是用大于减小数,故需要实现一个cmp函数

​ (2)其次由于保证了是大数减小数,故不存在剩一位的情况,一定能减得下,故一定会被存进答案里

​ (3)由于高位在后,低位在前,故有可能存在前导零,故需要取前导零。

3、高精度乘法

描述:

​ 求一个大正整数与一个数的乘积。

思路:

(1)用可变长数组vector存储A

(2)将字符串a逆序存入数组A中
(3)高精度乘法的构造:
(3.1)定义一个答案数组,并且初始化进位t
(3.2)从头到尾遍历大数A,
(3.3)将每一位与b的乘积的计算结果放入t中
(3.4)将t % 10的结果放入答案数组的末尾
(3.5)更新进位t
(3.6)看进位t是否还有数,如果还有,就在答案数组末尾加入该数
(3.7)去前导0
(4)逆序输出答案数组即可

代码模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <vector>

using namespace std;

vector<int> mul(vector<int> A, int b)
{
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i ++)
{
if (i < A.size()) t += A[i] * b;

C.push_back(t % 10);
t /= 10;
}

if (t) C.push_back(t);
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}

int main()
{
string a;
vector<int> A;
int b;
cin >> a >> b;

for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');

auto C = mul(A, b);

for (int i = C.size() - 1; i >= 0; i --) cout << C[i];


return 0;
}
注意:

​ (1)由于可能最后的答案可能为0,故需要去除前导零的情况。

​ (2)由于可能最后一位计算后大于了10,还没有进位,故需要判断是否还有剩位,有则直接放在答案末尾即可。

4、高精度除法

描述:

​ 求一个一个非负大整数A与一个整数b的商和余数。

思路:

高精度除法:大数A / 小数b
(1)用可变长数组vector存储A
(2)将字符串a逆序存入数组A中
(3)构造高精度除法
(3.1)定义答案数组,以及初始化余数t,由于余数最后要输出, 可以定义成全局变量
(3.2)从后往前遍历大数(大数是逆序存储到数组的,但这里除法需要从高位开始计算,所以从最后一位即大数的高位开始)
(3.3)每一位数 + 余数 * 10 ,进行计算
(3.4)将上一步的结果 除 b 的结果放入答案数组
(3.5)最后更新余数 t %= b
(3.6)将答案数组翻转,因为最后的输出是逆序输出的
(3.7)去前导0
(4)逆序输出答案数组即可

代码模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int t;
vector<int> div(vector<int> A, int b)
{
vector<int> C;

t = 0;

for (int i = A.size() - 1; i >= 0; i --)
{
t = A[i] + t * 10;
C.push_back(t / b);
t %= b;
}

reverse(C.begin(), C.end());
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}

int main()
{
string a;
int b;
cin >> a >> b;
vector<int> A;
for (int i = a.size() - 1; i >= 0; i --) A.push_back(a[i] - '0');

auto C = div(A, b);

for (int i = C.size() - 1; i >= 0; i --) cout << C[i];
cout << endl << t;
return 0;

}
注意:

​ (1)由于做除法只能从高位做,且模板都是逆序存,逆序输出,为了统一模板,则在除法模板中写的有些复杂

​ (2)除法模板与其他模板不同,需要逆序逐位除,即高位往低位算

​ (3)算出来之后,由于我们需要逆序输出,故我们要将求出来的答案用reverse进行翻转

​ (4)然后由于可能前几位除不下,故需要进行去前导零。


高精度算法
http://example.com/2023/04/05/基础算法/高精度算法/
作者
Feng Tao
发布于
2023年4月5日
更新于
2023年4月21日
许可协议