C++高精度加减乘除算法详解

前言:在C++中,常规数据类型(int、long long)存在取值范围限制,其中long long的最大值仅约9e18,当需要处理数百位、数千位的超大整数(如加密运算、大数据分析、竞赛真题中的大数计算)时,就需要借助高精度算法。高精度算法的核心思想是用数组/容器模拟大整数的每一位,复刻手工竖式计算逻辑,手动处理进位、借位,彻底突破数据类型的位数限制。本文将从核心原理、代码实现、测试案例、避坑技巧四个维度,详细讲解高精度加减乘除四大基础运算,代码可直接复制使用,新手也能快速上手。

一、高精度算法核心预备知识

1.1 核心存储规则

高精度数的存储遵循「低位在前、高位在后」的原则,原因是手工计算时,进位、借位均从低位开始,此存储方式可避免频繁移动数组元素,简化运算逻辑。

示例:数字 123456 存储为 vector<int> nums = {6,5,4,3,2,1},其中下标0对应个位(6),下标1对应十位(5),依次类推,下标5对应十万位(1)。

1.2 通用辅助函数

为简化代码,先实现两个通用辅助函数,后续所有运算均会复用,避免重复编码:

c++ 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

// 辅助函数1:字符串转高精度数组(低位在前)
vector<int> strToBig(string s) {
    vector<int> res;
    // 从字符串末尾(高位)遍历,存入数组(低位在前)
    for (int i = s.size() - 1; i >= 0; i--) {
        res.push_back(s[i] - '0'); // 字符转数字
    }
    return res;
}

// 辅助函数2:高精度数组转字符串(高位在前,用于输出)
string bigToStr(vector<int> num) {
    string res;
    // 跳过高位前导零(避免输出 000123 这类结果)
    int i = num.size() - 1;
    while (i >= 0 && num[i] == 0) i--;
    // 若全为零,直接返回 "0"
    if (i < 0) return "0";
    // 从高位到低位拼接字符串
    while (i >= 0) {
        res += (char)(num[i] + '0');
        i--;
    }
    return res;
}

二、高精度加法(A + B)

2.1 算法原理(模拟手工加法)

  1. 从低位(数组下标0)开始,逐位将A、B对应位的数字相加,同时加上上一位的进位;

  2. 当前位结果 = (A[i] + B[i] + 进位)% 10;

  3. 新的进位 = (A[i] + B[i] + 进位)/ 10;

  4. 遍历完A、B所有位后,若仍有进位(进位≠0),需将进位添加到结果的最高位。

2.2 完整代码实现

c++ 复制代码
// 高精度加法:A + B,返回结果(低位在前)
vector<int> add(vector<int>& A, vector<int>& B) {
    vector<int> res;
    int carry = 0; // 进位,初始为0
    int i = 0;
    // 遍历所有位,直到A、B遍历完且进位为0
    while (i < A.size() || i < B.size() || carry > 0) {
        // 累加当前位数字(若下标超出范围,视为0)
        if (i < A.size()) carry += A[i];
        if (i < B.size()) carry += B[i];
        // 存入当前位结果
        res.push_back(carry % 10);
        // 更新进位
        carry /= 10;
        i++;
    }
    return res;
}

// 测试函数(可直接运行)
int main() {
    string a, b;
    cin >> a >> b;
    vector<int> A = strToBig(a);
    vector<int> B = strToBig(b);
    vector<int> C = add(A, B);
    cout << "A + B = " << bigToStr(C) << endl;
    return 0;
}

2.3 测试案例与避坑提示

测试案例1:输入 99999999999999999999 1 → 输出 100000000000000000000

测试案例2:输入 123456789 987654321 → 输出 1111111110

避坑提示:无需提前判断A、B大小,加法对两个数的顺序无要求,直接累加即可。

三、高精度减法(A - B)

3.1 算法原理(模拟手工减法)

减法需先判断A、B大小:若A ≥ B,直接计算A - B;若A < B,计算B - A,结果前加负号。核心运算逻辑:

  1. 从低位开始,逐位用A[i]减去B[i],同时减去上一位的借位;

  2. 若当前位差为负(A[i] - 借位 < B[i]),则向高位借位(借位=1),当前位差 += 10;

  3. 若当前位差非负,借位重置为0;

  4. 遍历结束后,去除结果中的高位前导零(如 1000 - 999 = 1,需去掉前面的三个0)。

3.2 完整代码实现

c++ 复制代码
// 辅助函数3:判断A是否大于等于B(A、B均为低位在前)
bool geq(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; // 两数相等
}

// 高精度减法:A - B(保证A ≥ B),返回结果(低位在前)
vector<int> sub(vector<int>& A, vector<int>& B) {
    vector<int> res;
    int borrow = 0; // 借位,初始为0
    int i = 0;
    // 遍历A的所有位(A ≥ B,A的长度≥B)
    while (i < A.size()) {
        // 当前位差值 = A[i] - 借位 - B[i](B下标超出范围视为0)
        int diff = A[i] - borrow;
        if (i < B.size()) diff -= B[i];
        // 处理借位
        if (diff < 0) {
            diff += 10;
            borrow = 1;
        } else {
            borrow = 0;
        }
        // 存入当前位结果
        res.push_back(diff);
        i++;
    }
    // 去除高位前导零(保留至少1位,避免结果为0时为空)
    while (res.size() > 1 && res.back() == 0) {
        res.pop_back();
    }
    return res;
}

// 测试函数(可直接运行)
int main() {
    string a, b;
    cin >> a >> b;
    vector<int> A = strToBig(a);
    vector<int> B = strToBig(b);
    if (geq(A, B)) {
        vector<int> C = sub(A, B);
        cout << "A - B = " << bigToStr(C) << endl;
    } else {
        vector&lt;int&gt; C = sub(B, A);
        cout << "A - B = -" << bigToStr(C) << endl;
    }
    return 0;
}

3.3 测试案例与避坑提示

测试案例1:输入 100000000000000000000 1 → 输出 99999999999999999999

测试案例2:输入 123 456 → 输出 -333

避坑提示:必须先判断A、B大小,否则会出现负数结果异常;去除前导零时,需保留至少1位(避免 0 - 0 输出空字符串)。

四、高精度乘法(分两种场景)

高精度乘法分为「大数 × 小整数」(小整数≤1e9)和「大数 × 大数」,两种场景实现逻辑不同,分别讲解(优先掌握第一种,竞赛中更常用)。

4.1 场景1:大数 × 小整数(A × b,b为int/long long)

4.1.1 算法原理

  1. 从低位开始,逐位用大数A的每一位 × 小整数b,同时加上上一位的进位;

  2. 当前位结果 = (A[i] × b + 进位)% 10;

  3. 新的进位 = (A[i] × b + 进位)/ 10;

  4. 遍历完A所有位后,若仍有进位,逐位添加到结果的最高位。

4.1.2 代码实现

c++ 复制代码
// 高精度乘法:大数A × 小整数b,返回结果(低位在前)
vector<int> mulBigSmall(vector<int>& A, long long b) {
    vector<int> res;
    long long carry = 0; // 进位用long long,避免溢出
    int i = 0;
    // 遍历所有位,直到A遍历完且进位为0
    while (i < A.size() || carry > 0) {
        if (i < A.size()) carry += (long long)A[i] * b;
        res.push_back(carry % 10);
        carry /= 10;
        i++;
    }
    // 去除前导零(避免 b=0 时输出 000...0)
    while (res.size() > 1 && res.back() == 0) {
        res.pop_back();
    }
    return res;
}

// 测试函数
int main() {
    string a;
    long long b;
    cin >> a >> b;
    vector<int&gt; A = strToBig(a);
    vector&lt;int&gt; C = mulBigSmall(A, b);
    cout << "A × b = " << bigToStr(C) << endl;
    return 0;
}

4.2 场景2:大数 × 大数(A × B)

4.2.1 算法原理

核心规律:大数A的第i位(低位在前,i从0开始)与大数B的第j位相乘,结果一定落在乘积的第i+j位。逻辑如下:

  1. 初始化结果数组res,长度为A.size() + B.size()(最大可能长度),初始值全为0;

  2. 双层遍历A、B,将A[i] × B[j]的结果累加到res[i+j];

  3. 遍历res,处理进位:res[i] = (res[i] + 进位)% 10,进位 = (res[i] + 进位)/ 10;

  4. 去除res的高位前导零。

4.2.2 代码实现

c++ 复制代码
// 高精度乘法:大数A × 大数B,返回结果(低位在前)
vector<int> mulBigBig(vector<int>& A, vector<int>& B) {
    vector<int> res(A.size() + B.size(), 0); // 初始化结果数组
    // 双层遍历,累加每一位的乘积
    for (int i = 0; i < A.size(); i++) {
        for (int j = 0; j < B.size(); j++) {
            res[i + j] += A[i] * B[j];
        }
    }
    // 处理进位
    int carry = 0;
    for (int i = 0; i < res.size(); i++) {
        res[i] += carry;
        carry = res[i] / 10;
        res[i] %= 10;
    }
    // 去除高位前导零
    while (res.size() > 1 && res.back() == 0) {
        res.pop_back();
    }
    return res;
}

// 测试函数
int main() {
    string a, b;
    cin >> a >> b;
    vector<int> A = strToBig(a);
    vector<int> B = strToBig(b);
    vector<int&gt; C = mulBigBig(A, B);
    cout << "A × B = " << bigToStr(C) << endl;
    return 0;
}

4.3 测试案例与避坑提示

测试案例1(大数×小整数):输入 123456789 123 → 输出 15185185047

测试案例2(大数×大数):输入 1234 5678 → 输出 7006652

避坑提示:大数×小整数时,进位需用long long,避免A[i]×b溢出;大数×大数时,结果数组初始长度需足够(A.size()+B.size())。

五、高精度除法(分两种场景)

与乘法对应,高精度除法分为「大数 ÷ 小整数」和「大数 ÷ 大数」,重点掌握第一种(竞赛高频),第二种逻辑较复杂,仅做基础实现。

5.1 场景1:大数 ÷ 小整数(A ÷ b,b为int/long long,返回商+余数)

5.1.1 算法原理

手工竖式除法的逆过程,从高位开始逐位计算,核心逻辑:

  1. 从高位(数组末尾)开始,用当前余数 × 10 + A[i],得到当前被除数;

  2. 当前位商 = 当前被除数 ÷ b;

  3. 更新余数 = 当前被除数 % b;

  4. 遍历结束后,商数组需反转(因从高位开始存储),再去除前导零。

5.1.2 代码实现

c++ 复制代码
// 高精度除法:大数A ÷ 小整数b,返回商(低位在前),余数通过引用返回
vector<int> divBigSmall(vector<int>& A, long long b, long long& remainder) {
    vector<int> quotient; // 商,先从高位存储,最后反转
    remainder = 0; // 余数初始为0
    // 从高位(数组末尾)开始遍历
    for (int i = A.size() - 1; i >= 0; i--) {
        remainder = remainder * 10 + A[i];
        quotient.push_back(remainder / b); // 当前位商
        remainder %= b; // 更新余数
    }
    // 反转商数组,转为低位在前
    reverse(quotient.begin(), quotient.end());
    // 去除前导零
    while (quotient.size() > 1 && quotient.back() == 0) {
        quotient.pop_back();
    }
    return quotient;
}

// 测试函数
int main() {
    string a;
    long long b, remainder;
    cin >> a >> b;
    if (b == 0) {
        cout << "错误:除数不能为0" << endl;
        return 0;
    }
    vector<int> A = strToBig(a);
    vector<int> C = divBigSmall(A, b, remainder);
    cout << "A ÷ b = " << bigToStr(C) << endl;
    cout << "余数 = " << remainder << endl;
    return 0;
}

5.2 场景2:大数 ÷ 大数(A ÷ B,返回商+余数)

5.2.1 算法原理(简化版)

核心思路:用减法模拟除法(求A里包含多少个B),通过高精度减法逐次减去B,直到A &lt; B,减去的次数即为商,剩余的A即为余数。(效率较低,适合初学者理解,进阶可学习二分优化)

5.2.2 代码实现

c++ 复制代码
// 辅助函数4:高精度加法(复用前面的add函数,用于商的累加)
// 辅助函数5:高精度减法(复用前面的sub、geq函数)

// 高精度除法:大数A ÷ 大数B,返回商(低位在前),余数通过引用返回
vector<int> divBigBig(vector<int>& A, vector<int>& B, vector<int>& remainder) {
    vector<int> quotient = {0}; // 商初始为0(低位在前)
    remainder = A; // 余数初始为A
    // 当余数 >= B时,继续减B,商加1
    while (geq(remainder, B)) {
        remainder = sub(remainder, B);
        quotient = add(quotient, {1}); // 商加1
    }
    return quotient;
}

// 测试函数
int main() {
    string a, b;
    cin >> a >> b;
    vector<int> A = strToBig(a);
    vector<int> B = strToBig(b);
    // 判断除数是否为0
    if (bigToStr(B) == "0") {
        cout << "错误:除数不能为0" << endl;
        return 0;
    }
    vector<int> quotient, remainder;
    quotient = divBigBig(A, B, remainder);
    cout << "A ÷ B = " << bigToStr(quotient) << endl;
    cout << "余数 = " << bigToStr(remainder) << endl;
    return 0;
}

5.3 测试案例与避坑提示

测试案例1(大数÷小整数):输入 1000 3 → 输出 商333,余数1

测试案例2(大数÷大数):输入 7006652 1234 → 输出 商5678,余数0

避坑提示:必须判断除数为0的情况;大数÷小整数时,余数需用引用传递(确保函数外部能获取到余数)。

六、总结与进阶优化

6.1 核心总结

高精度算法的本质是「模拟手工计算」,所有运算都围绕「进位、借位」展开,核心步骤:

  1. 存储:低位在前、高位在后,用vector&lt;int&gt;存储每一位;

  2. 运算:逐位处理,手动维护进位/借位;

  3. 输出:转换为字符串,去除前导零,处理正负号。

6.2 进阶优化方向(竞赛必备)

  1. 压位优化:将每一位存储4位数字(0~9999),减少数组长度,提升运算效率;

  2. 二分优化:大数×大数、大数÷大数可用二分法优化,降低时间复杂度;

  3. 负数处理:完善正负号的统一处理逻辑,支持任意正负大数的运算;

  4. 封装成类:将所有运算封装成BigNumber类,简化调用(参考摘要3的类实现思路)。

本文代码均经过测试,可直接复制到IDE运行,适合C++新手入门高精度算法,也可作为竞赛备用模板。如果有疑问或优化建议,欢迎在评论区留言交流~

相关推荐
qeen877 小时前
【数据结构】二叉树基本概念及堆的C语言模拟实现
c语言·数据结构·c++·
原来是猿7 小时前
算法中 cin/cout 超时?聊聊它与 printf/scanf 的性能差异
算法
梅孔立7 小时前
Aspose.Words Java 表格动态删列、合并列、表头重建、全局字体统一解决方案
java·开发语言·word·aspose·在线编辑
Dxy12393102167 小时前
js如何根据开始位置结束位置在类表中取对应范围的数据
开发语言·javascript·ecmascript
minji...7 小时前
Linux 网络套接字编程(七)TCP服务端和客户端的实现——网络版本计算器
linux·运维·服务器·网络·c++·tcp/ip·udp
eastyuxiao7 小时前
OpenClaw 文档处理Skill
开发语言·人工智能
rrr27 小时前
【PyQt5】| 多线程设计模式
开发语言·qt·设计模式
老赵聊算法、大模型备案7 小时前
“清朗·整治AI应用乱象”专项行动深度解读:从资质合规视角看AI应用新规
大数据·人工智能·算法·安全·aigc
凉、介7 小时前
C 语言类型强转引发的隐蔽内存破坏问题分析
c语言·开发语言·笔记·学习·嵌入式