算法札记:C++ __int128

老纸不想写高精度

故学了下__int128

**_int128 (有符号)_**‌

  • 类型:128位有符号整数
  • 最大能存:约 170,141,183,460,469,231,731,687,303,715,884,105,727 (约 1.7 × 10³⁸)
  • 十进制大约能存 39 位数。

‌**不过,用的时候有两点要特别注意:**‌

  1. 它不是标准C++ ‌:__int128 是 GCC 和 Clang 编译器的扩展,Visual Studio 的 MSVC 编译器不支持。在竞赛或Linux环境下通常没问题。
  2. 输入输出麻烦 ‌:你不能直接用 cincoutscanfprintf 来读写 __int128,需要自己写专门的快读快写函数。

输入输出

方法一:手写快读快写函数(最常用)

这是竞赛中最常见的方式,直接调用 read()write() 函数:

cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

// 快读
__int128 read() {
    __int128 x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

// 快写
void write(__int128 x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

int main() {
    __int128 a = read();
    __int128 b = read();
    write(a + b);
    return 0;
}

方法二:重载 >><< 运算符

重载之后就可以像普通类型一样直接用 cin/cout 了,写起来更顺手:

cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

// 重载输入
istream& operator>>(istream& is, __int128& n) {
    string s;
    is >> s;
    n = 0;
    bool neg = false;
    int i = 0;
    if (s == '-') {
        neg = true;
        i = 1;
    }
    for (; i < s.size(); i++) {
        n = n * 10 + (s[i] - '0');
    }
    if (neg) n = -n;
    return is;
}

// 重载输出
ostream& operator<<(ostream& os, __int128 n) {
    if (n == 0) return os << "0";
    if (n < 0) {
        os << '-';
        n = -n;
    }
    string s;
    while (n) {
        s.push_back('0' + n % 10);
        n /= 10;
    }
    reverse(s.begin(), s.end());
    return os << s;
}

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

需要注意的点

  • 编译器限制 ‌:__int128 是 GCC 和 Clang 的扩展,MSVC(Visual Studio)不支持,在 Linux 或竞赛环境(如洛谷、Codeforces)中通常没问题。
  • 性能 ‌:重载运算符内部用字符串转换,效率比快读快写稍低,但一般够用。如果数据量极大(比如百万级),建议用 getchar/putchar 版本的快读快写。
  • 负数处理‌:写函数时别忘了处理负号,否则输出会出错。

还不如写高精度呢,超