【C++】高精度模板

宇宙免责申明:

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

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

在 C++ 中,内置整数类型(intlong 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. 除数 blong 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 小时前
003003002_WPF Grid 基类官方类定义逐行深度解析
开发语言·windows·算法·c#·wpf·visual studio
xieliyu.2 小时前
Java 线程池入门详解:线程池基础定义 + ThreadPoolExecutor 全参构造方法逐参数解析
java·开发语言·idea·javaee
一条泥憨鱼2 小时前
【从0开始学习计算机网络】| HTTP方法疑点解析
开发语言·计算机网络·http
我不是懒洋洋3 小时前
从零实现一个分布式计算:MapReduce的核心设计
c++
aaaameliaaa10 小时前
字符函数和字符串函数
c语言·笔记·算法
微学AI11 小时前
一根针指向所有方向:挂谷猜想对 LLM Agent 技能-记忆架构的启示
开发语言·人工智能·架构·挂谷猜想
城管不管11 小时前
ReAct、Plan-and-Execute、Reflection 三大智能 Agent 范式核心区别
java·人工智能·算法·spring·ai·动态规划
月疯11 小时前
二分法算法(水平等分图形面积)
算法
豆瓣鸡11 小时前
算法日记 - Day3
java·开发语言·算法