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 &lt; 0islower() 的定义不是很好。

替代方案,对安静的迂腐警告进行一些强制转换,并且可能会加快 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哈希函数

我如何将 djb2 映射到哈希表?

c_cpp 在C中进行djb2哈希测试,使控制台能够测试哈希值

为啥 5381 和 33 在 djb2 算法中如此重要?

量子计算求解函数因子:Bernstein-Vazirani Algorithm

量子计算求解函数因子:Bernstein-Vazirani Algorithm