如何可移植实现64位宽转128位乘法的高64位计算?
实现64位整数宽乘法取高64位(无符号/有符号)
要求用仅依赖stdint.h的可移植C代码,模拟x86-64的mul和imul指令行为,计算两个64位整数的128位乘积后返回高64位,且无未定义行为。
无符号版本:uint64_t mul128hi(uint64_t lhs, uint64_t rhs)
实现思路
将64位整数拆分为高32位和低32位,利用乘法展开式计算:
设 lhs = a << 32 | b,rhs = c << 32 | d(a、b、c、d均为32位无符号数),则:
lhs * rhs = (a*c) << 64 | ((a*d + b*c) << 32) | (b*d)
高64位由三部分组成:a*c、(a*d + b*c + (b*d的高32位))右移32位的结果,需处理中间进位避免溢出。
代码实现
#include <stdint.h> uint64_t mul128hi(uint64_t lhs, uint64_t rhs) { // 拆分64位为高/低32位 const uint32_t a = (uint32_t)(lhs >> 32); const uint32_t b = (uint32_t)lhs; const uint32_t c = (uint32_t)(rhs >> 32); const uint32_t d = (uint32_t)rhs; // 计算四个32x32乘积(结果为64位,无溢出) const uint64_t ac = (uint64_t)a * c; const uint64_t ad = (uint64_t)a * d; const uint64_t bc = (uint64_t)b * c; const uint64_t bd = (uint64_t)b * d; // 计算中间项:ad + bc + bd的高32位 const uint64_t mid = ad + bc + (bd >> 32); // 高64位 = ac + mid的高32位 + mid低32位向高32位的进位 return ac + (mid >> 32) + ((mid & 0xFFFFFFFF) > (0xFFFFFFFF - (ac & 0xFFFFFFFF)) ? 1 : 0); }
有符号版本:int64_t imul128hi(int64_t lhs, int64_t rhs)
实现思路
基于无符号乘法结果,结合补码规则修正符号:
有符号数的128位乘积高64位,等于无符号乘积的高64位,加上符号修正项——若lhs为负则减去rhs,若rhs为负则减去lhs(利用补码负数的符号位扩展特性)。
代码实现
int64_t imul128hi(int64_t lhs, int64_t rhs) { // 先按无符号计算高64位 const uint64_t unsigned_result = mul128hi((uint64_t)lhs, (uint64_t)rhs); // 符号修正:负数的补码特性,需减去对应操作数 int64_t result = (int64_t)unsigned_result; if (lhs < 0) { result -= rhs; } if (rhs < 0) { result -= lhs; } return result; }
对应x86-64指令说明
imul r8:64位有符号乘法,将rax与r8相乘,结果存入r12:r8(128位),函数返回r12部分。mul r8:64位无符号乘法,将rax与r8相乘,结果存入r12:r8(128位),函数返回r12部分。
内容的提问来源于stack exchange,提问作者l-m
相关产品推荐
相关产品推荐

