【杂谈】------使用 __int128 处理超大整数计算
一、整数类型的表示范围
常见整数类型在 C++ 中的表示范围如下(带符号):
当然可以,下面是在你的基础上添加了“字节”这一列的完整表格:
类型 | 位数 | 字节数 | 表示范围(最大值约等于) |
---|---|---|---|
int | 32 | 4 | 231 − 1 ≈ 2.1×10⁹ |
long long | 64 | 8 | 263 − 1 ≈ 9.2×10¹⁸ |
__int128 | 128 | 16 | 2127 − 1 ≈ 1.7×10³⁸ |
二、数值膨胀的来源
假设你要处理如下乘积(三角形代价计算):
w[i] * w[k] * w[j]
而每个权值最大为 10^9
,则:
最大乘积 = 10^9 × 10^9 × 10^9 = 10^27
三、long long
无法表示 10^27
long long
的最大值是:
2^63 − 1 ≈ 9.2 × 10^18
而 10^27
是其 约 10^8 倍,远远超出范围。
如果继续用 long long
,即使只计算一次这样的乘法,也必定溢出。
四、使用 __int128
是最佳解决方案
__int128
的最大值约为:
2^127 ≈ 1.7 × 10^38
而你只需表示 10^27
,绰绰有余,因此推荐使用 __int128
。
五、__int128
的使用方法
1. 定义变量
__int128 a = 1234567890123456789;
__int128 b = a * a;
使用别名方便阅读:
using lll = __int128;
lll x = 1;
2. 四则运算
和普通整数一样操作:
__int128 a = 1e12;
__int128 b = a * a; // 1e24
__int128 c = b / 1000000;
3. 输出函数(重点)
由于 cout
不支持 __int128
,需手动转换为字符串输出:
// 函数:print128
// 功能:输出 __int128 类型的整数(128位整数)
// 参数:x - 要输出的 __int128 类型的数
void print128(__int128 x)
{// 特判:如果是 0,直接输出并返回if (x == 0) {cout << "0";return;}// 如果是负数,先输出负号,然后取相反数变成正数if (x < 0) {cout << "-";x = -x;}string s; // 用于存储每一位数字(逆序)// 将整数转为字符串(注意是从低位往高位推)while (x > 0) {s += (x % 10) + '0'; // 取最低位,并转成字符存入字符串x /= 10; // 去掉最低位}// 当前字符串是反着的,需要反转成正常顺序reverse(s.begin(), s.end());// 输出最终的字符串cout << s;
}
4. 输入函数(重点)
// 函数:read128
// 功能:从标准输入读取一个整数(可以是负数),并将其转换为 __int128 类型返回
__int128 read128()
{string s;cin >> s; // 从标准输入读取一个字符串,代表一个整数(可能为负数)bool neg = false; // 用于标记输入的数字是否为负数int i = 0; // 遍历字符串的起始位置// 如果字符串的首字符是负号,则标记为负数if (s[0] == '-') {neg = true; // 记录负号标志i = 1; // 从下标 1 开始处理数字部分}__int128 res = 0; // 初始化结果为 0,用于保存转换后的整数值// 遍历字符串的每一位数字字符for (; i < s.size(); i++) {// 将字符转换为对应数字('0' → 0, '1' → 1, ..., '9' → 9)// 并将其累加到结果中(相当于 res = res * 10 + 当前数字)res = res * 10 + (s[i] - '0');}// 如果是负数,则结果取相反数return neg ? -res : res;
}
5. 示例程序:三数乘积
#include <bits/stdc++.h>
using namespace std;//输出函数板子:
void print128(__int128 x)
{if (x == 0) {cout << "0";return;}if (x < 0) {cout << "-";x = -x;}string s;while (x > 0) {s += (x % 10) + '0';x /= 10; }reverse(s.begin(), s.end());cout << s;
}int main()
{long long a, b, c;cin >> a >> b >> c;//注意隐式类型提升 与 强制类型转换的结合 问题__int128 res = (__int128)a * b * c;print128(res);cout << "\n";return 0;
}
6.隐式类型提升 与 强制类型转换
- 类型提升(Promotion):当一个表达式中涉及多个不同整数类型(如 int、long、long long、__int128)时,C++ 会自动将较小的类型提升到更大的类型,以保证运算的精度和正确性。
- 强制类型转换:如
__int128 res = (__int128)a * b * c;
即:只要表达式中有一个是 __int128,那么整个表达式就会被提升为 __int128 运算。
7. 编译方式
只要你使用 GCC 或 Clang,直接编译即可:
g++ -std=c++17 -O2 yourcode.cpp -o yourcode
⚠️ 注意:
__int128
在 Windows 的 MSVC 编译器 中不支持,仅适用于 Linux/macOS 下的 GCC 或 Clang。
六、总结
操作 | 支持情况 |
---|---|
定义变量 | ✅ 支持 |
四则运算 | ✅ 支持 |
比较操作 | ✅ 支持 |
cin/cout 支持 | ❌ 不支持,需要自写 |
GCC/Clang 支持 | ✅ 支持 |
MSVC 支持 | ❌ 不支持 |
七、替代方案(仅当不能用 __int128
时)
- 手写大整数类(如字符串模拟乘法)
- 使用 GMP 等大整数库(重量级方案)