int和long long因位宽固定(32/64位)易静默溢出,无法准确表示如50!或2^100等大数;高精度需字符串模拟竖式运算,加法逐位进位,乘法双循环定位i+j位,注意去前导零。

为什么 int 和 long long 不够用
因为 C++ 内置整型有固定位宽:int 通常 32 位(最大约 21 亿),long long 一般 64 位(最大约 9×10¹⁸)。一旦运算结果超过这个范围,就会静默溢出——不报错、不警告,只保留低比特位,结果完全错误。比如计算 factorial(50) 或 2^100,直接用内置类型得到的只是个毫无意义的余数。
手写高精度加法和乘法的关键点
核心思路是把大数当字符串存,按位模拟竖式运算。加法相对简单,乘法则容易漏掉进位或错位。
- 加法:从末位开始逐位相加,用
carry记录进位,结果字符数组要预留一位防最高位进位 - 乘法:必须两层循环,外层遍历乘数每一位,内层遍历被乘数每一位;结果位置是
i + j(从右往左索引),不是i * j - 别忘了最后去除前导零,但至少保留一位(如结果为 0)
- 负号单独处理,先取绝对值运算,再根据符号规则补上
示例片段(加法核心逻辑):
string add(string a, string b) {
if (a.length() < b.length()) swap(a, b);
int carry = 0;
for (int i = 0; i < b.length(); ++i) {
int sum = (a[a.length()-1-i] - '0') + (b[b.length()-1-i] - '0') + carry;
a[a.length()-1-i] = '0' + (sum % 10);
carry = sum / 10;
}
// ... 处理剩余位和最终进位
}用 boost::multiprecision::cpp_int 真正省事吗
能用,但要注意它不是“零成本抽象”。cpp_int 默认是动态分配的任意精度整数,小数值也会触发堆内存分配,性能比原生类型慢一个数量级以上。
立即学习“C++免费学习笔记(深入)”;
- 若只做少量大数运算(如密码学参数验证),开销可接受
- 若在循环里高频使用(如 DP 中每步都算大数),会显著拖慢速度,且可能引发频繁内存分配抖动
- 编译需链接 Boost,部分嵌入式或竞赛环境不支持
- 输出时默认不带前导零,但输入字符串不能含空格或非法字符,否则构造失败静默转为 0
基本用法:
#include <boost/multiprecision/cpp_int.hpp> using namespace boost::multiprecision; cpp_int a = "12345678901234567890"; cpp_int b = 98765432109876543210; cout << a * b << endl; // 自动处理精度
竞赛或刷题中该选哪种方案
国内 OJ(如洛谷、Codeforces)几乎都不允许用 Boost,必须手写。而且题目往往只要求输出结果某几位(如最后 100 位)、或模某个数,这时根本不需要完整高精度。
- 如果只需模
10^k,用long long配合每步取模即可(注意乘法中间结果可能溢出,用__int128或分治取模) - 如果只需判断大小或比较,可存为字符串按长度和字典序比较
- 真要输出完整十进制结果,且位数可控(≤ 10⁴),手写 vector
存 1000 进制比存单数字更省内存、更快 - 别在
operator+里反复push_back字符——预分配空间或逆序计算再反转
最常被忽略的一点:输入的大数字符串可能含前导零,但手写运算时若没清除,会导致长度误判,尤其在减法和除法中引发下标越界或死循环。


















