了解散列算法的位和字节
Posted
技术标签:
【中文标题】了解散列算法的位和字节【英文标题】:Understanding bits and bytes of a hashing algorithm 【发布时间】:2021-08-04 10:09:33 【问题描述】:在question 中关于一个名为 djb2 的非常简单的散列算法,作者想知道为什么在算法中选择了数字 33(参见下面的 C 代码)。
unsigned long;
hash(unsigned char *str)
unsigned long hash = 5381;
int c;
while (c = *str++) //just the character
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
在最佳答案中,第 2 点谈到了散列累加器以及它如何制作自己的两个副本,然后它谈到了传播。
有人能解释一下“复制自己”和答案2的“传播”是什么意思吗?
【问题讨论】:
【参考方案1】:第 2 步被引用是这样的:
从移位和加法实现中可以看出,使用 33 会复制哈希累加器中的大部分输入位,然后将这些位分散到相对较远的位置。这有助于产生良好的雪崩。使用较大的移位将复制较少的位,使用较小的移位将使位交互更加局部,并使交互传播所需的时间更长。
33 是 32+1。这意味着,由于乘法是可分配的,hash * 33 = (hash * 32) + (hash * 1)
- 或者换句话说,制作 hash
的两个副本,将其中一个向左移动 5 位,然后将它们相加,这就是 (hash << 5) + hash
在更直接的方式。
【讨论】:
这是否假设我们正在处理 64 位机器?如果是这样,我们可以对每个字执行更多操作,从而减少对磁盘的 I/O?我的意思是,为什么答案 2 很重要? @GoldenRetriever 64 位并不是必需的,而且 djb2 的设计也没有考虑到这一点(不可能,它可以追溯到 1991 年)。我们当然可以使用更多的算术运算来计算出更好的散列。djb2 不是一个非常高质量的散列,尤其是与现代 64 位散列相比 1.难道我们不能使用除 33 之外的另一个乘法并仍然获得两个副本吗? 2. 为什么当使用更大的移位时,它会复制更少的位,反之亦然? 任何 2 的 2 次方之和都会产生两个副本(您可以使用更多副本进行更多混合)。较大的移位会从哈希顶部丢弃更多位,并且不要混合哈希的最低位。实际上可以包含大班次,但仅次大班班效果会很差。将0x80000001
视为乘数,会非常糟糕。
位移5是乘以32,这里乘以33是因为hash
本身也加了以上是关于了解散列算法的位和字节的主要内容,如果未能解决你的问题,请参考以下文章