我正在尝试使用带有三个有符号整数的unordered_map作为键(这是因为我希望使用tbb的concurrent_unordered_map)。
我将这个小(3x16位=> 64位)函数放在一起:
// to hash
int64_t result = int16_t(x);
result = int64_t(result << 16) + int16_t(y);
result = int64_t(result << 16) + int16_t(z);
// from hash
int16_t x_ = int16_t(result >> 32);
int16_t y_ = int16_t(result >> 16);
int16_t z_ = int16_t(result & 0xFFFF);
这不起作用,我在这里犯了什么错误?
我的数字分布使得更接近于零的负数或正数更可能(通常小于+/- 2 ^ 8),但我想将其扩展到最多2 ^ 32的范围,而不是我的2 ^ 16例子。理想情况下,我在寻找典型范围内的极少碰撞,最好是简单的算法。有什么建议吗?
答案 0 :(得分:3)
您的问题是您正在执行位操作并添加已签名的数字。如果数字为负数,则加法运算将转换为减法。在那之后很难梳理出正确的原始值。
考虑:
int16_t x = -1, y = 2, z = -3;
int64_t result = x; // result: FFFFFFFFFFFFFFFF
result = (result << 16) + y; // result: FFFFFFFFFFFF0000 + 0002
result = (result << 16) + z; // result: FFFFFFFF00020000 - 0003
return result; // result: FFFFFFFF0001FFFD
因此,虽然保留了-1
和-3
,但减法的结果已将2
减少为1
。
相反,您应该限制对无符号值的操作。对于无符号值,+
和|
在您的代码中将是等效的,因为您要添加到0
填充的数字部分。
int64_t hash () {
uint64_t result = uint16_t(x_);
result = (result << 16) + uint16_t(y_);
result = (result << 16) + uint16_t(z_);
return result;
}