此答案显示了如何在不支持 128 位整数的系统上从 64x64 位乘法中获得(确切的)前 64 位。 @amdn 的回答将在确实支持 128 位整数的系统上提供更好的性能。
下图显示了一种从两个 64 位数字计算 128 位乘积的方法。每个黑色矩形代表一个 64 位数字。该方法的 64 位输入 X 和 Y 被划分为标记为 a、b、c 和 d 的 32 位块。然后执行四次 32x32 位乘法,得到标记为 a*c、b*c、a*d 和 b*d 的四个 64 位乘积。四个乘积必须移位并相加才能计算出最终答案。
请注意,128 位乘积的低 32 位完全由部分乘积 b*d 的低 32 位决定。接下来的 32 位由下面的低 32 位决定
mid34 = ((b*c) & 0xffffffff) + ((a*d) & 0xffffffff) + ((b*d) >> 32);
请注意,mid34 是三个 32 位数字的和,因此实际上是一个 34 位的和。 mid34 的高两位作为进位到 64x64 位乘法的高 64 位。
这将我们带到演示代码。 top64 函数计算 64x64 乘法的高 64 位。允许在注释中显示低 64 位的计算有点冗长。 main 函数利用 128 位整数通过一个简单的测试用例来验证结果。进一步的测试留给读者作为练习。
#include <stdio.h>
#include <stdint.h>
typedef unsigned __int128 uint128_t;
uint64_t top64( uint64_t x, uint64_t y )
{
uint64_t a = x >> 32, b = x & 0xffffffff;
uint64_t c = y >> 32, d = y & 0xffffffff;
uint64_t ac = a * c;
uint64_t bc = b * c;
uint64_t ad = a * d;
uint64_t bd = b * d;
uint64_t mid34 = (bd >> 32) + (bc & 0xffffffff) + (ad & 0xffffffff);
uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32);
// uint64_t lower64 = (mid34 << 32) | (bd & 0xffffffff);
return upper64;
}
int main( void )
{
uint64_t x = 0x0000000100000003;
uint64_t y = 0x55555555ffffffff;
uint128_t m = x, n = y;
uint128_t p = m * n;
uint64_t top = p >> 64;
printf( "%016llx %016llx\n", top, top64( x, y ) );
}