【C++】高精度模板

宇宙免责申明:

  1. 本文由deepseek做过更改,以及进行了语言上的优化,可能会出现错误,如有错误,请私信联系.
  2. 目前高精度加法的先别抄,可能有问题.

高精度计算四则运算模板详解(C++)

在 C++ 中,内置整数类型(int、long long)能表示的数值范围有限(long long 最大约 9.22×10189.22\times 10^{18}9.22×1018)。当我们需要处理远超此范围的整数(例如几百位的大数)时,就必须用数组或字符串模拟手算过程,这就是高精度计算。

本文基于我常用的四份模板代码,分别实现高精度加法、减法、乘法 (高精×高精)以及高精度除以低精度(高精÷低精,返回商和余数)。所有代码均以字符串读入,输出字符串结果,逻辑清晰,适合竞赛或工程使用。

总思路:模拟竖式的加减乘除的方法.


一、高精度加法

思路

模拟竖式加法:

  1. 将两个数字字符串按从低位到高位 (即个位在前)存入 vector<int>。
  2. 从低位到高位逐位相加,同时维护进位 jw。
  3. 每一位结果为 (a[i] + b[i] + jw) % 10,进位为 /10。
  4. 最后如果进位非零,补到最高位。
  5. 将结果倒序转回字符串。

代码(函数模板)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

string a, b;

string gjadd(string x, string y)
{
    int lenx = x.size(), leny = y.size();
    int cs = max(lenx, leny); // 最长的位数
    vector<int> a, b, sum;

    // 倒序存储,个位在 index 0
    for (int i = lenx - 1; i >= 0; i--)
        a.push_back(x[i] - '0');
    for (int i = leny - 1; i >= 0; i--)
        b.push_back(y[i] - '0');

    int tmp = 0, jw = 0;
    for (int i = 0; i < cs; i++)
    {
        tmp = jw;
        if (i < lenx) tmp += a[i];
        if (i < leny) tmp += b[i];
        jw = tmp / 10;
        sum.push_back(tmp % 10);
    }
    if (jw != 0) sum.push_back(jw); // 最高位进位

    string ans = "";
    for (int i = sum.size() - 1; i >= 0; i--)
        ans += char(sum[i] + '0');
    return ans;
}

int main()
{
    cin >> a >> b;
    cout << gjadd(a, b);
    return 0;
}

注意

  • 无需去除前导零(加法不会产生多余零,除非 0+0=0,此时保留一个 0 是合理的)。
  • 支持任意长度,只需内存足够。

二、高精度减法

思路

模拟竖式减法,但需要先判断结果符号:

  1. 若被减数小于减数(长度短,或长度相等且字典序小),则交换两数,并在答案前加负号 "-"。
  2. 将两数倒序存入 vector。
  3. 从低位到高位逐位相减,若不够减则向高位借位(jw=1,当前位加 10)。
  4. 最后去除结果向量末尾的多余零(前导零)。
  5. 倒序输出,若之前标记了负号则先加上。

代码(函数模板)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

string a, b;

string gjsub(string x, string y)
{
    int lenx = x.size(), leny = y.size();
    string ans = "";
    // 判断符号,保证 x >= y
    if (lenx < leny)
    {
        ans += "-";
        swap(x, y);
        swap(lenx, leny);
    }
    else if (lenx == leny)
    {
        if (x < y) 
        {
            ans += "-";
            swap(x, y);
        }
    }

    int cs = max(lenx, leny);
    vector<int> a, b, sum;

    for (int i = lenx - 1; i >= 0; i--)
        a.push_back(x[i] - '0');
    for (int i = leny - 1; i >= 0; i--)
        b.push_back(y[i] - '0');

    int tmp = 0, jw = 0; // jw 为借位
    for (int i = 0; i < cs; i++)
    {
        tmp = a[i] - jw;
        if (i < leny) tmp -= b[i];
        if (tmp < 0)
        {
            jw = 1;
            tmp += 10;
        }
        else
        {
            jw = 0;
        }
        sum.push_back(tmp);
    }

    // 去除前导零(但至少保留一位)
    while ((int)sum.size() > 1 && sum.back() == 0)
        sum.pop_back();

    for (int i = sum.size() - 1; i >= 0; i--)
        ans += char(sum[i] + '0');

    return ans;
}

int main()
{
    cin >> a >> b;
    cout << gjsub(a, b);
    return 0;
}

注意

  • 比较两数大小时,长度不同直接比长度,长度相同用字符串字典序(C++ 的 string 比较与数值字典序一致,因为都是数字字符)。
  • 借位处理是关键:tmp = a[i] - jw - (i < leny ? b[i] : 0),若小于 0 则加 10 并标记借位。
  • 去前导零时,sum 是低位在前,所以末尾是最高位。

三、高精度乘法(高精 × 高精)

思路

模拟竖式乘法,使用卷积思想:

  1. 将两个数倒序存入 vector<int>。
  2. 双重循环,sum[i+j] += a[i] * b[j](不考虑进位)。
  3. 统一处理进位:从低位到高位,将每一位 sum[i] 的十位及以上进位到下一位。
  4. 去除结果末尾的前导零(高位零)。
  5. 倒序输出。

代码(函数模板)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

string a, b;

string gjmul(string x, string y)
{
    int lenx = x.size(), leny = y.size();
    int cs = lenx + leny; // 乘积最多 lenx+leny 位
    vector<int> a, b, sum(cs, 0);

    for (int i = lenx - 1; i >= 0; i--)
        a.push_back(x[i] - '0');
    for (int i = leny - 1; i >= 0; i--)
        b.push_back(y[i] - '0');

    // 无进位累乘
    for (int i = 0; i < lenx; i++)
        for (int j = 0; j < leny; j++)
            sum[i + j] += a[i] * b[j];

    // 统一进位
    int jw = 0;
    for (int i = 0; i < cs; i++)
    {
        int tmp = jw + sum[i];
        jw = tmp / 10;
        sum[i] = tmp % 10;
    }

    // 去除前导零(高位在末尾)
    while ((int)sum.size() > 1 && sum.back() == 0)
        sum.pop_back();

    string ans = "";
    for (int i = sum.size() - 1; i >= 0; i--)
        ans += char(sum[i] + '0');
    return ans;
}

int main()
{
    cin >> a >> b;
    cout << gjmul(a, b);
    return 0;
}

注意

  • 乘积位数最多为 lenx + leny,分配 sum 大小为 lenx+leny 可以保证进位不越界。
  • 进位处理放在双重循环之后,更简洁,且避免反复取模。
  • 去前导零时,如果结果为 0,保留一个 0。

四、高精度除以低精度(高精 ÷ 低精)

思路

模拟除法竖式,从高位到低位逐位求商:

  1. 除数 b 是 long long 类型(低精度)。
  2. 用字符串 x 存储被除数,从最高位开始,维护当前余数 ys。
  3. 每一步:tmp = ys * 10 + 当前位数字,商位 = tmp / b,余数更新为 tmp % b。
  4. 将所有商位存入 deque<int>,然后去除前导零(高位零)。
  5. 返回结构体 Number,包含商(字符串)和余数(long long)。

代码(函数模板)

cpp 复制代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;

string a;
int b;

struct Number
{
    string shang;
    ll yu;
};

Number gaochudi(string x, ll y)
{
    Number cur;

    // 除数为 0 时返回特殊标识
    if (y == 0LL)
    {
        cur.shang = "-1";
        cur.yu = 0;
        return cur;
    }

    int lenx = x.size();
    deque<int> a, sum;

    for (int i = 0; i < lenx; i++)
        a.push_back(x[i] - '0');

    ll ys = 0;
    for (int i = 0; i < lenx; i++)
    {
        ll tmp = ys * 10 + a[i];
        sum.push_back(tmp / y);
        ys = tmp % y;
    }

    // 去除前导零(高位在 front)
    while ((int)sum.size() > 1 && sum.front() == 0)
        sum.pop_front();

    string ans = "";
    for (int i = 0; i < (int)sum.size(); i++)
        ans += char(sum[i] + '0');

    cur.shang = ans;
    cur.yu = ys;
    return cur;
}

int main()
{
    cin >> a >> b;
    Number tp = gaochudi(a, b);
    cout << tp.shang << endl << tp.yu;
}

注意

  • 除数为 0 时,模板返回 "-1" 作为错误标识(实际使用时需注意)。
  • 因为低精度除法,余数 ys 不会超过 y-1,用 long long 足够。
  • 使用 deque 便于从头部弹出前导零,也可以改用 vector 然后反转。

五、综合对比与使用建议

运算 输入类型 输出类型 核心技巧
加法 两个字符串 字符串 倒序相加,处理进位
减法 两个字符串 字符串 判断符号,借位处理,去前导零
乘法 两个字符串 字符串 卷积累乘,统一进位,去前导零
除法(高精÷低精) 字符串 + long long 结构体(商+余数) 从高位模拟竖式,余数迭代

所有模板均以字符串作为输入输出,便于处理任意长度的大整数,且代码风格统一,易于集成。

改进扩展

  • 高精 ÷ 高精 需要更复杂的试商过程,此处未提供。
  • 可以增加负数支持(目前除法仅处理非负)。
  • 乘法可优化为 FFT(快速傅里叶变换)以处理超长位数,但模板中的 O(n2)O(n^2)O(n2) 对于几千位以内的竞赛题已足够。

六、测试样例

「注」:觉得信不过的可以拿去测一下

加法

输入:12345678901234567890 98765432109876543210

输出:111111111011111111100

减法

输入:10000000000000000000 1

输出:9999999999999999999

乘法

输入:123456789 987654321

输出:121932631112635269

除法 (高精 ÷ 低精)

输入:1234567890123456789 12345

输出:

100005098674803

3024 (余数)


希望这份博客能帮助你快速掌握高精度计算的核心。若有疑问,欢迎留言交流!

完整代码已全部使用你的模板,可直接复制使用。

相关推荐
坤坤子吖2 分钟前
算法学习——高精度加减乘除
c++·笔记·学习·算法
CQU_JIAKE9 分钟前
10.1[A]2267,磐久UMX【上下文128K,KVCache部分]
算法
言乐614 分钟前
Python实现关税自动计算模型
开发语言·python·django·virtualenv·pygame
朝朝辞暮i14 分钟前
C++ 第 14 课:引用 &
开发语言·c++·算法
白山编程大哥25 分钟前
适合初学者练习的 C/C++ 开源项目推荐
c语言·c++·开源
Joe_Wang534 分钟前
【从0到1学习JVM · 21】既不浪费空间又没有碎片,标记整理算法到底慢在哪
jvm·学习·算法·垃圾回收·标记整理算法
让学习成为一种生活方式40 分钟前
PlantCellChat--单细胞与空间转录组数据预测植物细胞间通讯的R包--The Plant Journal
算法
梅雅达编程笔记43 分钟前
04-Python CSV数据保存与翻页抓取
开发语言·爬虫·python·pandas·数据采集·csv
C++ 老炮儿的技术栈1 小时前
有符号变量与无符号变量的区别
服务器·开发语言·前端·数据结构·c++·算法·c
估值探索者1 小时前
【Python量化策略实战 #04】Donchian 通道假突破太多?用 ATR 阈值过滤跑通真实突破信号
开发语言·python·接口·api接口·数据api接口·股票数据api接口