Dan Bernstein 的 Djb2 哈希函数:当我们只能乘以 33 时,为啥还要使用按位运算符?
Posted
技术标签:
【中文标题】Dan Bernstein 的 Djb2 哈希函数:当我们只能乘以 33 时,为啥还要使用按位运算符?【英文标题】:Djb2 hash function by Dan Bernstein : Why use bitwise operator when we can just multiply by 33?Dan Bernstein 的 Djb2 哈希函数:当我们只能乘以 33 时,为什么还要使用按位运算符? 【发布时间】:2021-10-18 22:37:53 【问题描述】:在 Dan Bernstein 著名的 Djb2 哈希函数中,我看到使用按位运算符是首选,但为什么要使用它而不是简单的乘法呢?是不是更快?
(散列
// Hashes word to a number
unsigned int hash(const char *word)
// Djb2 hash function by Dan Bernstein
unsigned long hash = 5381;
int c;
while ((c = *word++))
hash = ((hash << 5) + hash) + tolower(c); /* hash * 33 + c */
return hash % N;
【问题讨论】:
欢迎来到 Stack Overflow。 softwareengineering.stackexchange.com/questions/234967/… 会回答你的问题吗? 您可能想检查您的 优化 asm 输出,因为如果在这种情况下该计算的 both 版本我不会感到惊讶最终生成相同的功能代码。 clang 12.01 和 gcc 11.2 都将生成 shift-arithmetic-left 5 和后续添加,无论您是否明确按照所示代码指定 或 仅使用 (hash * 33)。 任何现代编译器都会为两者生成相同的代码(godbolt 确认),但在 1991 年设计此算法时可能并非如此。 【参考方案1】:既然我们只能乘以 33,为什么还要使用位运算符? 但是为什么要在简单的乘法上使用它呢?是不是更快?
BITD,编译器没有那么智能,所以它通常更快。 @that other guy
今天,除非您的情况另有说明(例如,使用弱编译器),否则为清晰起见编写代码。无论哪种方式,一个好的编译器都会产生高效的代码。
hash = ((hash << 5) + hash) + tolower(c);
// or
hash = hash * 33u + tolower(c);
因为这是一个哈希,所以两者都一样清楚。
迂腐
如果c < 0
,islower()
的定义不是很好。
替代方案,对安静的迂腐警告进行一些强制转换,并且可能会加快 unsigned 代码。
unsigned hash(const char *word)
const unsigned char *uword = (const unsigned char *) word;
unsigned long hash = 5381u;
int c;
while ((c = *uword++))
hash = hash*33u + (unsigned)tolower(c);
return (unsigned) (hash % N);
【讨论】:
以上是关于Dan Bernstein 的 Djb2 哈希函数:当我们只能乘以 33 时,为啥还要使用按位运算符?的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp 在C中进行djb2哈希测试,使控制台能够测试哈希值