2775 字
14 分钟
C++高精度算法完全入门教程

C++高精度算法完全入门教程#

📚 什么是高精度算法?#

当我们需要计算超出 intlong long 范围的大数时,就需要用到高精度算法

为什么需要高精度?#

// int 最大值约为 2×10^9 (21亿)
// long long 最大值约为 9×10^18
// 但如果要计算:
// 123456789012345678901234567890 + 987654321098765432109876543210
// 这些数已经超出了 long long 的范围!

核心思想#

把大数用字符串或数组存储,模拟手算的过程!

就像我们小学学的竖式计算一样:

  • 加法:从右往左,逐位相加,满10进1
  • 减法:从右往左,逐位相减,不够就借位
  • 乘法:每一位分别相乘,再相加
  • 除法:模拟长除法的过程

🔧 准备工作#

数据存储方式#

我们用 vector 存储大数,每个元素存一位数字。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// 将字符串转换为数组(倒序存储,方便进位)
vector<int> stringToVector(string s) {
vector<int> num;
// 从后往前遍历,存入数组
for (int i = s.length() - 1; i >= 0; i--) {
num.push_back(s[i] - '0'); // 字符转数字
}
return num;
}
// 将数组转换为字符串(用于输出)
string vectorToString(vector<int> num) {
string s = "";
// 去除前导零
bool started = false;
for (int i = num.size() - 1; i >= 0; i--) {
if (num[i] != 0) started = true;
if (started) s += (num[i] + '0');
}
if (s == "") return "0"; // 特殊情况:结果为0
return s;
}

💡 为什么倒序存储? 因为加减法从个位开始,倒序存储后,索引0就是个位,方便处理进位!


➕ 高精度加法#

算法思路#

模拟手工竖式加法:

  1. 从最低位(个位)开始相加
  2. 如果和 ≥ 10,向高位进1
  3. 处理完所有位后,检查最高位是否还有进位

代码实现#

// 高精度加法:A + B
vector<int> add(vector<int> A, vector<int> B) {
vector<int> C; // 存储结果
int carry = 0; // 进位
// 处理所有位(取较长的长度)
for (int i = 0; i < A.size() || i < B.size(); i++) {
// 获取当前位的数字(如果越界则为0)
int x = (i < A.size()) ? A[i] : 0;
int y = (i < B.size()) ? B[i] : 0;
// 当前位的和 = A的当前位 + B的当前位 + 进位
int sum = x + y + carry;
// 存储当前位结果(取个位)
C.push_back(sum % 10);
// 计算进位(取十位)
carry = sum / 10;
}
// 处理最后的进位
if (carry > 0) {
C.push_back(carry);
}
return C;
}

使用示例#

int main() {
string a, b;
cout << "请输入两个大数:" << endl;
cin >> a >> b;
vector<int> A = stringToVector(a);
vector<int> B = stringToVector(b);
vector<int> C = add(A, B);
cout << "结果:" << vectorToString(C) << endl;
return 0;
}
// 输入:
// 123456789012345678901234567890
// 987654321098765432109876543210
// 输出:
// 1111111110111111111011111111100

➖ 高精度减法#

算法思路#

模拟手工竖式减法:

  1. 确保被减数 ≥ 减数(否则结果为负)
  2. 从最低位开始相减
  3. 如果当前位不够减,从高位借1(当前位+10)
  4. 去除结果前导零

比较大小函数#

// 比较两个大数:A >= B 返回true
bool compare(vector<int> A, vector<int> B) {
// 长度不同,长的大
if (A.size() != B.size()) {
return A.size() > B.size();
}
// 长度相同,从高位比较
for (int i = A.size() - 1; i >= 0; i--) {
if (A[i] != B[i]) {
return A[i] > B[i];
}
}
return true; // 相等返回true
}

减法实现#

// 高精度减法:A - B (要求 A >= B)
vector<int> subtract(vector<int> A, vector<int> B) {
vector<int> C;
int borrow = 0; // 借位
for (int i = 0; i < A.size(); i++) {
// 获取当前位的数字
int x = A[i];
int y = (i < B.size()) ? B[i] : 0;
// 当前位的差 = A的当前位 - B的当前位 - 借位
int diff = x - y - borrow;
// 如果不够减,借位
if (diff < 0) {
diff += 10; // 从高位借10
borrow = 1; // 标记借位
} else {
borrow = 0; // 不需要借位
}
C.push_back(diff);
}
// 去除前导零
while (C.size() > 1 && C.back() == 0) {
C.pop_back();
}
return C;
}

使用示例#

int main() {
string a, b;
cin >> a >> b;
vector<int> A = stringToVector(a);
vector<int> B = stringToVector(b);
// 确保 A >= B
if (!compare(A, B)) {
swap(A, B);
cout << "-"; // 结果为负数
}
vector<int> C = subtract(A, B);
cout << vectorToString(C) << endl;
return 0;
}
// 输入:1000000000000 999999999999
// 输出:1

✖️ 高精度乘法#

1. 高精乘单精(大数 × 小数)#

适用场景A 是大数,b 是普通整数(不超过 10^9)

算法思路#

1 2 3 4
× 5
---------
6 1 7 0

从低位到高位,每位都乘以 b,处理进位。

代码实现#

// 高精度乘单精度:A × b
vector<int> multiplyInt(vector<int> A, int b) {
vector<int> C;
int carry = 0; // 进位
// 遍历A的每一位
for (int i = 0; i < A.size(); i++) {
// 当前位乘以b,再加上进位
int product = A[i] * b + carry;
// 存储当前位结果
C.push_back(product % 10);
// 计算进位
carry = product / 10;
}
// 处理剩余进位
while (carry > 0) {
C.push_back(carry % 10);
carry /= 10;
}
// 去除前导零
while (C.size() > 1 && C.back() == 0) {
C.pop_back();
}
return C;
}

使用示例#

int main() {
string a;
int b;
cin >> a >> b;
vector<int> A = stringToVector(a);
vector<int> C = multiplyInt(A, b);
cout << vectorToString(C) << endl;
return 0;
}
// 输入:123456789 999
// 输出:123333333111

2. 高精乘高精(大数 × 大数)#

适用场景:两个数都是大数

算法思路#

模拟竖式乘法:

1 2 3
× 4 5 6
---------
7 3 8 (123 × 6)
6 1 5 0 (123 × 5, 左移1位)
4 9 2 0 0 (123 × 4, 左移2位)
---------
5 6 0 8 8

代码实现#

// 高精度乘高精度:A × B
vector<int> multiply(vector<int> A, vector<int> B) {
// 结果最多有 A.size() + B.size() 位
vector<int> C(A.size() + B.size(), 0);
// A的每一位 × B的每一位
for (int i = 0; i < A.size(); i++) {
for (int j = 0; j < B.size(); j++) {
// A[i] × B[j] 放在 C[i+j] 位置
C[i + j] += A[i] * B[j];
}
}
// 处理进位
for (int i = 0; i < C.size() - 1; i++) {
if (C[i] >= 10) {
C[i + 1] += C[i] / 10; // 进位
C[i] %= 10; // 保留个位
}
}
// 去除前导零
while (C.size() > 1 && C.back() == 0) {
C.pop_back();
}
return C;
}

使用示例#

int main() {
string a, b;
cin >> a >> b;
vector<int> A = stringToVector(a);
vector<int> B = stringToVector(b);
vector<int> C = multiply(A, B);
cout << vectorToString(C) << endl;
return 0;
}
// 输入:123456789 987654321
// 输出:121932631112635269

➗ 高精度除法(高精÷单精)#

算法思路#

模拟长除法:

-------
除数 | 被除数
-------
余数

从高位到低位处理,每次用当前余数×10 + 当前位,除以除数。

代码实现#

// 高精度除单精度:A ÷ b,返回商,r为余数
vector<int> divide(vector<int> A, int b, int &r) {
vector<int> C;
r = 0; // 余数初始化为0
// 从最高位开始除(注意:A是倒序存储的)
for (int i = A.size() - 1; i >= 0; i--) {
r = r * 10 + A[i]; // 当前余数
C.push_back(r / b); // 商的当前位
r %= 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 = stringToVector(a);
int remainder;
vector<int> C = divide(A, b, remainder);
cout << "商:" << vectorToString(C) << endl;
cout << "余数:" << remainder << endl;
return 0;
}
// 输入:123456789 999
// 输出:
// 商:123580
// 余数:369

🎯 完整代码示例#

将所有功能整合到一起:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
vector<int> stringToVector(string s) {
vector<int> num;
for (int i = s.length() - 1; i >= 0; i--) {
num.push_back(s[i] - '0');
}
return num;
}
string vectorToString(vector<int> num) {
string s = "";
bool started = false;
for (int i = num.size() - 1; i >= 0; i--) {
if (num[i] != 0) started = true;
if (started) s += (num[i] + '0');
}
return (s == "") ? "0" : s;
}
bool compare(vector<int> A, vector<int> B) {
if (A.size() != B.size()) return A.size() > B.size();
for (int i = A.size() - 1; i >= 0; i--) {
if (A[i] != B[i]) return A[i] > B[i];
}
return true;
}
vector<int> add(vector<int> A, vector<int> B) {
vector<int> C;
int carry = 0;
for (int i = 0; i < A.size() || i < B.size(); i++) {
int x = (i < A.size()) ? A[i] : 0;
int y = (i < B.size()) ? B[i] : 0;
int sum = x + y + carry;
C.push_back(sum % 10);
carry = sum / 10;
}
if (carry > 0) C.push_back(carry);
return C;
}
vector<int> subtract(vector<int> A, vector<int> B) {
vector<int> C;
int borrow = 0;
for (int i = 0; i < A.size(); i++) {
int x = A[i];
int y = (i < B.size()) ? B[i] : 0;
int diff = x - y - borrow;
if (diff < 0) {
diff += 10;
borrow = 1;
} else {
borrow = 0;
}
C.push_back(diff);
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
vector<int> multiplyInt(vector<int> A, int b) {
vector<int> C;
int carry = 0;
for (int i = 0; i < A.size(); i++) {
int product = A[i] * b + carry;
C.push_back(product % 10);
carry = product / 10;
}
while (carry > 0) {
C.push_back(carry % 10);
carry /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
vector<int> multiply(vector<int> A, vector<int> B) {
vector<int> C(A.size() + B.size(), 0);
for (int i = 0; i < A.size(); i++) {
for (int j = 0; j < B.size(); j++) {
C[i + j] += A[i] * B[j];
}
}
for (int i = 0; i < C.size() - 1; i++) {
if (C[i] >= 10) {
C[i + 1] += C[i] / 10;
C[i] %= 10;
}
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
vector<int> divide(vector<int> A, int b, int &r) {
vector<int> C;
r = 0;
for (int i = A.size() - 1; i >= 0; i--) {
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}
reverse(C.begin(), C.end());
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main() {
cout << "=== C++高精度计算器 ===" << endl;
cout << "1.加法 2.减法 3.乘法(×小数) 4.乘法(×大数) 5.除法" << endl;
int choice;
cin >> choice;
string a, b;
vector<int> A, B, C;
if (choice == 1) {
cin >> a >> b;
A = stringToVector(a);
B = stringToVector(b);
C = add(A, B);
cout << vectorToString(C) << endl;
}
else if (choice == 2) {
cin >> a >> b;
A = stringToVector(a);
B = stringToVector(b);
if (!compare(A, B)) {
swap(A, B);
cout << "-";
}
C = subtract(A, B);
cout << vectorToString(C) << endl;
}
else if (choice == 3) {
int num;
cin >> a >> num;
A = stringToVector(a);
C = multiplyInt(A, num);
cout << vectorToString(C) << endl;
}
else if (choice == 4) {
cin >> a >> b;
A = stringToVector(a);
B = stringToVector(b);
C = multiply(A, B);
cout << vectorToString(C) << endl;
}
else if (choice == 5) {
int num, remainder;
cin >> a >> num;
A = stringToVector(a);
C = divide(A, num, remainder);
cout << "商:" << vectorToString(C) << endl;
cout << "余数:" << remainder << endl;
}
return 0;
}

📝 练习题目推荐#

入门级#

  1. A+B Problem (大数版) - Luogu P1601
  2. A-B Problem (大数版) - Luogu P2142
  3. 高精度乘法 - Luogu P1303

进阶级#

  1. 阶乘计算 - 计算 n! (n ≤ 1000)
  2. 斐波那契数列 - 计算第 n 项 (n ≤ 10000)
  3. 大数幂运算 - 计算 a^b

💡 常见问题#

Q1: 为什么要倒序存储?#

A: 因为进位是从低位向高位进行的,倒序存储后,索引小的就是低位,方便从前往后遍历处理进位。

Q2: 如何判断结果为0?#

A: 如果去除前导零后,向量为空或只剩一个0,则结果为0。

Q3: 时间复杂度是多少?#

A:

  • 加减法:O(max(len(A), len(B)))
  • 乘法(高精×单精):O(len(A))
  • 乘法(高精×高精):O(len(A) × len(B))
  • 除法:O(len(A))

Q4: 可以用string代替vector吗?#

A: 可以,但vector操作更方便,尤其是处理进位时。


🎓 总结#

高精度算法的核心:

  1. 用数组/向量存储大数
  2. 模拟手工计算过程
  3. 注意处理进位/借位
  4. 去除前导零

记住:从简单到复杂,先理解原理,再写代码!

加油,算法新手们!💪


本文完整代码已在 GCC 11.4 测试通过

有问题欢迎在评论区讨论!

C++高精度算法完全入门教程
https://wuxie233.com/posts/cpp-high-precision/
作者
WuXie
发布于
2025-01-09
许可协议
CC BY-NC-SA 4.0