当前位置: 首页 > news >正文

C++ Int128 —— 128位有符号整数类实现剖析

🧠 C++ Int128 —— 128位有符号整数类实现剖析

引用:openppp2/ppp/Int128.h

🏗️ 1. 存储结构设计

Int128
+unsigned long long lo: 低64位数据存储
+signed long long hi: 高64位数据存储(带符号)
+...: 其他运算符
+Int128()
+Int128(signed char)
+Int128(unsigned long long)
+Int128(signed long long, unsigned long long)
+operator=()
+operator+()
+operator-()

内存布局解析

0        64       128 (位)
┌────────┬────────┐
│   lo   │   hi   │
└────────┴────────┘

设计特点

  • #pragma pack(push, 1) 确保16字节紧凑存储
  • 低64位(lo)使用无符号类型处理纯数据
  • 高64位(hi)使用有符号类型处理数值符号
  • 构造函数覆盖所有基础整数类型

➕ 2. 加法运算实现

算法流程图

溢出
未溢出
开始
计算低64位和
检测低64位溢出
高64位加1
直接计算高64位和
组合结果
返回结果

代码实现详解

inline Int128 operator+(const Int128& left, const Int128& right)
{Int128 value; // 创建临时结果对象value.lo = left.lo + right.lo; // 计算低64位和// 检测低64位是否溢出// 无符号数溢出时:a + b < aif (value.lo < left.lo) {value.hi = left.hi + right.hi + 1; // 进位处理} else {value.hi = left.hi + right.hi; // 无进位}return value;
}

关键技术点

  • 无符号整数溢出检测:a + b < a
  • 进位处理:高64位额外加1
  • 时间复杂度:O(1),性能接近原生加法

➖ 3. 减法运算实现

算法流程图

开始
对右操作数取负
执行加法操作
返回结果

取负操作实现

inline Int128 Int128::operator-() const
{Int128 x = *this; // 创建副本x.Negate(); // 执行取反操作return x;
}void Int128::Negate()
{hi = ~hi; // 高64位按位取反lo = ~lo; // 低64位按位取反(*this) += 1; // 加1完成补码转换
}

减法运算符实现

inline Int128 operator-(const Int128& left, const Int128& right)
{return left + (-right); // 利用补码原理:a - b = a + (-b)
}

关键技术点

  • 基于补码原理实现减法
  • 取负操作:按位取反后加1
  • 边界情况处理:最小负数取负后仍为自身

✖️ 4. 乘法运算实现

算法流程图

开始
处理操作数符号
分解为32位数组
双层循环乘法
处理进位
组合结果
应用符号
返回结果

代码实现详解

inline Int128 Int128::Multiply(Int128 left, Int128 right)
{// 处理符号int leftSign = left.Sign(); // 获取左操作数符号left = leftSign < 0 ? -left : left; // 转换为正数int rightSign = right.Sign(); // 获取右操作数符号right = rightSign < 0 ? -right : right; // 转换为正数// 分解为32位数组unsigned int xInts[4]; // 左操作数32位数组unsigned int yInts[4]; // 右操作数32位数组memcpy(xInts, &left.lo, 16); // 复制内存memcpy(yInts, &right.lo, 16); // 复制内存unsigned int mulInts[8] = {0}; // 乘积结果数组// 双层循环乘法for (int i = 0; i < 4; i++) {unsigned long long carry = 0; // 进位值for (int j = 0; j < 4; j++) {// 计算32位块乘积unsigned long long product = (unsigned long long)xInts[i] * yInts[j];// 累加乘积和进位unsigned long long sum = product + mulInts[i+j] + carry;// 存储低32位mulInts[i+j] = (unsigned int)sum;// 计算新进位carry = sum >> 32;}// 处理剩余进位int k = i + 4;while (carry) {unsigned long long sum = (unsigned long long)mulInts[k] + carry;mulInts[k] = (unsigned int)sum;carry = sum >> 32;k++;}}// 应用符号并返回结果return Int128(leftSign * rightSign, mulInts, 8);
}

关键技术点

  • 32位块分解避免64位乘法溢出
  • 小学乘法算法实现
  • 双重循环处理所有位组合
  • 进位链式处理

➗ 5. 除法与取模运算实现

算法流程图

开始
处理操作数符号
分解为32位数组
除数为单字?
简单除法
归一化操作数
Knuth算法D
试商计算
乘减操作
结果负?
加回调整
存储商
反归一化
组合结果
应用符号
返回结果

核心代码实现

inline Int128 Int128::DivRem(Int128 dividend, Int128 divisor, Int128& remainder)
{// 处理除数为零if (divisor == 0) return 0;// 处理符号int dividendSign = dividend.Sign();dividend = dividendSign < 0 ? -dividend : dividend;int divisorSign = divisor.Sign();divisor = divisorSign < 0 ? -divisor : divisor;// 分解为32位数组unsigned int u[4]; // 被除数数组unsigned int v[4]; // 除数数组memcpy(u, &dividend.lo, 16);memcpy(v, &divisor.lo, 16);unsigned int quotient[4] = {0}; // 商数组unsigned int rem[4] = {0}; // 余数数组// 执行无符号除法DivModUnsigned(u, v, quotient, rem);// 构造结果remainder = Int128(1, rem, 4); // 余数return Int128(dividendSign * divisorSign, quotient, 4); // 商
}

Knuth算法D关键步骤

void Int128::DivModUnsigned(unsigned int* u, unsigned int* v, unsigned int*& q, unsigned int*& r)
{int m = GetLength(u, 4); // 被除数有效长度int n = GetLength(v, 4); // 除数有效长度if (n <= 1) {// 单字除数特殊处理unsigned long long rem = 0;unsigned int v0 = v[0];for (int j = m - 1; j >= 0; j--) {rem = (rem << 32) + u[j]; // 组合当前值q[j] = (unsigned int)(rem / v0); // 计算商rem %= v0; // 更新余数}r[0] = (unsigned int)rem;}else if (m >= n) {// 归一化int shift = GetNormalizeShift(v[n-1]);unsigned int un[4] = {0};unsigned int vn[4] = {0};Normalize(u, m, un, shift);Normalize(v, n, vn, shift);// Knuth算法D主循环for (int j = m - n; j >= 0; j--) {// 试商计算unsigned long long rr = (unsigned long long)un[j+n] * Base32 + un[j+n-1];unsigned int qhat = (unsigned int)(rr / vn[n-1]);unsigned long long rhat = rr % vn[n-1];// 试商调整while (qhat >= Base32 || (qhat * vn[n-2] > (rhat * Base32 + un[j+n-2]))) {qhat--;rhat += vn[n-1];if (rhat >= Base32) break;}// 乘减操作signed long long borrow = 0;for (int i = 0; i < n; i++) {unsigned long long p = (unsigned long long)qhat * vn[i];signed long long t = un[i+j] - borrow - (p & 0xFFFFFFFF);un[i+j] = (unsigned int)t;borrow = (p >> 32) - (t >> 32);}borrow = un[j+n] - borrow;un[j+n] = (unsigned int)borrow;// 结果调整if (borrow < 0) {qhat--;unsigned long long carry = 0;for (int i = 0; i < n; i++) {carry = (unsigned long long)vn[i] + un[i+j] + carry;un[i+j] = (unsigned int)carry;carry >>= 32;}un[j+n] += (unsigned int)carry;}// 存储商q[j] = qhat;}// 反归一化Unnormalize(un, r, shift);}else {// 被除数小于除数memset(q, 0, 16); // 商为零memcpy(r, u, 16); // 余数为被除数}
}

关键技术点

  • 归一化提高数值稳定性
  • 试商算法减少迭代次数
  • 乘减操作实现精确计算
  • 反归一化恢复正确余数

🧮 6. 位运算实现

6.1 按位取反 (~)

输入值
对lo取反
对hi取反
组合结果
inline Int128 operator~(const Int128& value)
{return Int128(~value.hi, ~value.lo); // 高低位分别取反
}

6.2 左移 (<<)

开始
处理零位移
计算块移位
计算位内移位
处理低64位
处理高64位
处理跨块位移
组合结果
返回结果
inline Int128 operator<<(const Int128& value, int shift)
{// 处理零位移if (shift == 0) return value;// 计算实际位移shift %= 128; // 规范化位移// 分解为64位块unsigned long long* values = (unsigned long long*)&value.lo;// 计算块移位和位内移位int shiftOffset = shift / 64; // 整块移位int bshift = shift % 64; // 块内移位unsigned long long shifted[2] = {0}; // 结果数组// 处理低64位if (shiftOffset == 0) {shifted[0] = values[0] << bshift;if (bshift > 0) {shifted[1] = values[0] >> (64 - bshift);}}// 处理高64位if (shiftOffset <= 1) {int idx = shiftOffset;shifted[idx] |= values[1] << bshift;if (bshift > 0 && idx < 1) {shifted[idx+1] = values[1] >> (64 - bshift);}}return Int128((signed long long)shifted[1], shifted[0]);
}

6.3 右移 (>>)

开始
处理零位移
处理符号扩展
计算块移位
计算位内移位
处理高64位
处理低64位
处理跨块位移
组合结果
返回结果
inline Int128 operator>>(const Int128& value, int shift)
{// 处理零位移if (shift == 0) return value;// 计算实际位移shift %= 128; // 规范化位移// 处理整块移位unsigned long long* values = (unsigned long long*)&value.lo;if (shift >= 64) {int blockShift = shift / 64;shift %= 64;// 移动整块values[0] = values[1];// 符号扩展values[1] = (unsigned long long)((signed long long)values[1] >> 63);}// 块内移位处理int bshift = 64 - shift; // 补位位数unsigned long long shifted[2] = {0};// 高64位处理(带符号扩展)shifted[1] = (unsigned long long)((signed long long)values[1] >> shift);// 低64位处理shifted[0] = values[0] >> shift;if (shift > 0) {shifted[0] |= values[1] << bshift;}return Int128((signed long long)shifted[1], shifted[0]);
}

6.4 按位与 (&)、或 (|)、异或 (^)

操作数A
lo部分运算
hi部分运算
组合结果
// 按位与
inline Int128 operator&(const Int128& left, const Int128& right)
{return Int128(left.hi & right.hi, left.lo & right.lo);
}// 按位或
inline Int128 operator|(const Int128& left, const Int128& right)
{return Int128(left.hi | right.hi, left.lo | right.lo);
}// 按位异或
inline Int128 operator^(const Int128& left, const Int128& right)
{return Int128(left.hi ^ right.hi, left.lo ^ right.lo);
}

🛠️ 7. 关键辅助算法实现

7.1 归一化技术

开始
计算移位值
左移操作数
处理进位
返回归一化结果
inline void Int128::Normalize(unsigned int* u, int l, unsigned int* un, int shift)
{unsigned int carry = 0; // 进位值if (shift > 0) {int rshift = 32 - shift; // 右移位数for (int i = 0; i < l; i++) {unsigned int ui = u[i]; // 当前值un[i] = (ui << shift) | carry; // 左移并合并进位carry = ui >> rshift; // 计算新进位}// 处理剩余进位if (carry != 0) {un[l] = carry;}} else {// 无移位直接复制for (int i = 0; i < l; i++) {un[i] = u[i];}}
}

7.2 长度计算

开始
从高位扫描
找到第一个非零值
返回有效长度
inline int Int128::GetLength(unsigned int* uints, int uintslen)
{int index = uintslen - 1; // 从最高位开始// 跳过前导零while (index >= 0 && uints[index] == 0) {index--;}return index + 1; // 返回有效长度
}

🔄 8. 类型转换实现

在这里插入图片描述

// 布尔转换
inline Int128::operator bool() const
{return lo != 0 || hi != 0; // 任意位非零即为真
}// 64位整数转换
inline Int128::operator unsigned long long() const
{return lo; // 仅使用低64位
}// 32位整数转换
inline Int128::operator unsigned int() const
{return (unsigned int)lo; // 截断到32位
}

📝 9. 字符串转换实现

9.1 数值转字符串

开始
处理符号
转换为无符号数
进制转换
字符映射
构建字符串
返回结果

9.2 字符串转数值

开始
跳过空白
处理符号
按位解析
进制转换
累加结果
应用符号
返回结果

🏁 总结

Int128类的实现展示了以下核心技术:

  1. 紧凑存储结构:16字节内存布局
  2. 算术运算实现
    • 加法:溢出检测与进位处理
    • 减法:补码转换技巧
    • 乘法:32位块分解与进位链
    • 除法:Knuth算法D与归一化技术
  3. 位运算实现
    • 移位:块处理与跨块位移
    • 逻辑运算:分高低位处理
  4. 辅助算法
    • 归一化提高数值稳定性
    • 有效长度计算优化性能
  5. 类型转换
    • 显式转换保证安全性
    • 低64位截断处理

文章转载自:

http://DMjPcr4U.ymyhg.cn
http://uVUaWh5m.ymyhg.cn
http://nXtKHXR6.ymyhg.cn
http://AVQ9JPJf.ymyhg.cn
http://7XJAMGaX.ymyhg.cn
http://fW4H3aYX.ymyhg.cn
http://7QHg9iA3.ymyhg.cn
http://O71uEtSh.ymyhg.cn
http://jFjztLj7.ymyhg.cn
http://yc63CEGN.ymyhg.cn
http://VvL3BjrD.ymyhg.cn
http://WJJuTnHf.ymyhg.cn
http://UhoscekO.ymyhg.cn
http://hN1m26Wr.ymyhg.cn
http://sEtAoU22.ymyhg.cn
http://pNlZdjbY.ymyhg.cn
http://ccalTpAM.ymyhg.cn
http://07Ad7AjJ.ymyhg.cn
http://Xv7qiOn9.ymyhg.cn
http://XX5m3EQb.ymyhg.cn
http://rYkM83Il.ymyhg.cn
http://4kU3LouS.ymyhg.cn
http://c1vH4NQe.ymyhg.cn
http://o0DP8CCC.ymyhg.cn
http://1WFDUeNr.ymyhg.cn
http://9Anam45a.ymyhg.cn
http://7oAclcbJ.ymyhg.cn
http://x4cEN5B7.ymyhg.cn
http://cQ4r1CLg.ymyhg.cn
http://CsylWTLC.ymyhg.cn
http://www.dtcms.com/a/374275.html

相关文章:

  • 前端部署,又有新花样?
  • Neural Jacobian Field学习笔记 - omegaconf
  • C++(day8)
  • 设计模式:模板方法模式
  • 英发睿能闯关上市:业绩波动明显,毅达创投退出,临场“移民”
  • 华清远见25072班网络编程day1
  • 深入理解 AbstractQueuedSynchronizer (AQS):Java 并发的排队管家
  • 32位CPU架构是如何完成两数(32位)相加的指令的?
  • 深度学习中的损失函数都有哪些,大模型时代主要用的损失函数有哪些,中间有什么区别?
  • java:io流相关类的继承关系梳理
  • PAT 1004 Counting Leaves
  • Linux操作系统shell脚本语言-第六章
  • 基于Springboot + vue3实现的小区物业管理系统
  • 自动化测试DroidRun
  • 把一段 JSON 字符串还原成一个实体对象
  • YOLO系列论文梳理(AI版)
  • ARM内核知识概念
  • 图论相关经典题目练习及详解
  • 深圳比斯特|多维度分选:圆柱电池品质管控的自动化解决方案
  • MySQL 日志全解析:Binlog/Redo/Undo 等 5 类关键日志的配置、作用与最佳实践
  • 龙虎榜——20250908
  • 自噬机制解析(二):一文厘清 LC3/Atg8 概念及实验应用要点
  • java类加载过程
  • 20250908-02:运行第一个 LLM 调用程序
  • 基于A2A和ADK的内容规划代理
  • 电流源电路
  • 随机获取数组内任意元素
  • ESNP LAB 笔记:配置MPLS(Part4)
  • 发布工业智能体,云从科技打造制造业AI“运营大脑”
  • Flask 博客系统(Flask Blog System)