从64x64位乘法获得最高64位的合理便携方式?

时间:2014-11-10 20:29:54

标签: c++ c

在C / C ++中是否有一种合理的可移植方式来为128位结果乘以两个64位整数并得到结果的 top 64位,而不是底部的64位位?我需要这个来在任意大小的表上分配哈希函数。

3 个答案:

答案 0 :(得分:7)

这个答案显示了如何在不支持128位整数的系统上从64x64位乘法得到(精确)前64位。 @amdn的答案将在支持128位整数的系统上提供更好的性能。

下图显示了一种从两个64位数字计算128位乘积的方法。每个黑色矩形代表一个64位数字。方法的{64}输入XY被分为32位块,标记为abc和{{ 1}}。然后执行四次32x32位乘法运算,得到四个标记为da*cb*ca*d的64位产品。必须移动并添加四个产品以计算最终答案。

enter image description here

请注意,128位产品的低32位仅由部分乘积b*d的低32位决定。接下来的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