将int16_t散列到uint64_t

时间:2018-12-12 17:09:42

标签: c hash hash-function signed-integer

我正在尝试为VersionName = Commerical or Open Source Software创建哈希函数。函数原型如下:

int16_t

到目前为止,我已经知道了,但是我不知道这是否是正确的方法:

uint64_t hash_int16_t(const void *key);

是否有用于签名类型的哈希函数?我应该使用16位无符号整数或64位无符号整数混合位就可以了吗?如果整数为负数,将信息转换为无符号类型时会丢失信息吗?这会产生不确定的行为吗?

P.S。代码在C语言中,我从here中提取了哈希函数。

编辑1:自变量为uint64_t hash_int16_t(const void *key) { // key is expected to be an int16_t const int16_t *e = (const int16_t*)key; uint64_t x = (uint64_t)*e; x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); x = x ^ (x >> 31); return x; } ,因为允许用户将键存储为其他值,例如结构或字符串。上面的功能将增加对const void *key键的支持。

编辑2:我要完成的工作是通用哈希表。初始化哈希表时,用户将必须提供哈希函数,并且上面的示例与哈希表捆绑在一起。

1 个答案:

答案 0 :(得分:0)

  

是否有用于签名类型的哈希函数?

好的。一个适用于无符号类型的良好哈希函数也可以在带符号类型上正常工作。如果哈希函数很好,那么它的uniformity也很好,因此将特定位称为“符号位”还是“仅另一位”并不重要。出于这个答案的目的,我将假定您在链接线程中找到的算法为“好”。

  

我应该使用16位无符号整数或64位无符号整数混合位吗?

您不能依靠移位运算符来提升将uint16_t转换为uint64_t的结果,因此您必须像发布的代码中那样使用uint64_t

  

如果整数为负数,我将信息转换为无符号类型时会丢失信息吗?

否,因为int16_t的每个可能值在转换为uint64_t时都映射为不同的值:范围[0,32767]映射为[0,32767],范围[- 32768,-1]映射到[1844674407370951818848,18446744073709551615](有关说明,请参见下文)。

  

这会产生不确定的行为吗?

不。 C标准(C11)为有符号到无符号整数转换(第6.3.1.3节)指定了以下内容:

  

[...]如果新类型是无符号的,则通过重复添加或减去比新类型可表示的最大值多一个值来转换值,直到该值在新类型的范围内为止。

因此,-32768转换为-32768 + 2 64 = 18446744073709518848,并且-1转换为-1 + 2 64 = 18446744073709551615。


对于算法本身...如果哈希值仅用于创建哈希表,则哈希函数不需要具有任何 cryptographic 属性(例如分散)。因此,这种微不足道的算法可能对int16_t x来说就可以了:

return (uint64_t) x;

该功能没有分散,但是(通常)对于输入和输出范围具有最佳的均匀性。这是否可以接受将取决于哈希表的实现。如果它天真地仅使用哈希值的某些位来选择将值放入其中的bin,并且它本身不进行任何混合,则无论在何处,您都需要将输出的一致性集中在这些位上无论是谁。