在C / C ++中是否有一种合理的可移植方式来为128位结果乘以两个64位整数并得到结果的 top 64位,而不是底部的64位位?我需要这个来在任意大小的表上分配哈希函数。
答案 0 :(得分:7)
这个答案显示了如何在不支持128位整数的系统上从64x64位乘法得到(精确)前64位。 @amdn的答案将在做支持128位整数的系统上提供更好的性能。
下图显示了一种从两个64位数字计算128位乘积的方法。每个黑色矩形代表一个64位数字。方法的{64}输入X
和Y
被分为32位块,标记为a
,b
,c
和{{ 1}}。然后执行四次32x32位乘法运算,得到四个标记为d
,a*c
,b*c
和a*d
的64位产品。必须移动并添加四个产品以计算最终答案。
请注意,128位产品的低32位仅由部分乘积b*d
的低32位决定。接下来的32位由以下
b*d
请注意,mid34 = ((b*c) & 0xffffffff) + ((a*d) & 0xffffffff) + ((b*d) >> 32);
是三个32位数的总和,因此实际上是一个34位的总和。 mid34
的高两位用作64x64位乘法的前64位的进位。
这将我们带到演示代码中。 mid34
函数计算64x64乘法的高64位。允许在注释中显示较低64位的计算有点冗长。 top64
函数利用128位整数通过简单的测试用例验证结果。进一步的测试留给读者练习。
main
答案 1 :(得分:2)
一个小代数永远不会受伤:
#include <stdint.h>
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;
return a * c + ((b * d >> 32) + (a * d) + (b * c)) >> 32 +
((((a * d) & 0xFFFFFFFF) + ((b *c) & 0xFFFFFFFF) + ((b * d) >> 32)) >> 32);
}
答案 2 :(得分:2)
gcc和clang都支持128位整数作为扩展名。
这是实现目标的唯一方法demo
#include <iostream>
#include <cstdint>
//https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/_005f_005fint128.html#_005f_005fint128
using u128 = unsigned __int128;
using u64 = uint64_t;
void mul64x64( u64 a, u64 b, u64 & hi, u64 & lo ) {
u128 product = u128(a) * b;
lo = product;
hi = product >> 64;
}
int main()
{
u64 hi, lo;
mul64x64( 40282220, u64{1} << 63, hi, lo );
std::cout << hi << std::endl;
}
输出
set -x ; clang++ -std=c++11 -O0 -Wall -Werror main.cpp && ./a.out
+ clang++ -std=c++11 -O0 -Wall -Werror main.cpp
+ ./a.out
20141110