为啥像djb2这样的hash,与ulong一起使用时,会大于32位

Posted

技术标签:

【中文标题】为啥像djb2这样的hash,与ulong一起使用时,会大于32位【英文标题】:Why can a hash such as djb2, when used with a ulong, be larger than 32 bits为什么像djb2这样的hash,与ulong一起使用时,会大于32位 【发布时间】:2021-10-22 23:12:35 【问题描述】:
unsigned long hash(char *str) 

    unsigned long hash = 5381;
    int c;
    while ((c = *str++))
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    return hash % NUM_BUCKETS;

使用此代码,当您在函数中输入 20 个字母(例如 zzzzzzzzzzzzzzzzzzzzzzzzzzzz)时,您会得到一个巨大数字的输出。如果限制为仅 32 位,long 如何保存数字?

【问题讨论】:

you get an output of a huge number 您如何准确地检查输出的大小? printf(what here?)? 这能回答你的问题吗? djb2 Hash Function 【参考方案1】:

您应该首先检查unsigned long 32 位。如果您获得的值超过(大约)42 亿,那么几乎可以肯定它比这更宽(a)

您可以通过编译和运行以下程序来检查

#include <limits.h>
#include <stdio.h>

int main(void) 
    printf("%d\n%zu\n", CHAR_BIT, sizeof(unsigned long));
    return 0;

第一个值是字节中的位数,第二个值是unsigned long 中的字节数。因此,将两者相乘将得到unsigned long 类型中的位数。

在我的系统上,我得到 88,表示 64 位大小。


(a) ISO C 标准没有规定 C 中原始类型的确切大小(尽管它可能适用于 uint32_t 之类的东西)。事实上,它甚至根本没有直接规定位数。

什么是任务是最小范围要求,对于unsigned long0..4294967295(我之前提到的42亿)。

但是,一个实现可以免费为您提供更大的东西,例如 128 位类型,它可以为您提供从零到大约 1038 或一亿的范围百万百万。

顺便说一句,我本可以使用了数十亿、数万亿甚至数亿,但是:

有时对于它们所代表的十的实际幂存在分歧;和 许多“百万”后缀的使用比单个很少知道的后缀(如“undecillion”或“sextillion”)更大。

【讨论】:

【参考方案2】:

unsigned long 至少 32 位,但它可以更大。它是一种 64 位类型,大多数编译器在大多数 64 位处理器上运行,Windows 除外。所以返回 unsigned long 的函数可以返回大于 232 的值。

但是,您显示的函数保证返回一个范围从 0NUM_BUCKETS 的数字。如果您看到大于NUM_BUCKETS 的值,则您看到的不是此函数返回的值。也许您的代码中有错误。确保你已经在你的编译器上启用了所有合理的警告并且你已经正确地解决了它们(而不是盲目地添加强制转换)。如果您仍然不了解程序的输出,请使用调试器并检查中间值。如果你仍然不明白你的程序在做什么,你可以在线提问,complete code that reproduces the problem。

【讨论】:

以上是关于为啥像djb2这样的hash,与ulong一起使用时,会大于32位的主要内容,如果未能解决你的问题,请参考以下文章

Dan Bernstein 的 Djb2 哈希函数:当我们只能乘以 33 时,为啥还要使用按位运算符?

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

djb2:一个产生简单的随机分布的哈希函数

如果我们可以使用 Selenium,为啥还需要像 BeautifulSoup 这样的解析器?

为啥 Rails 不能与 mod_ruby 一起工作?

为啥链表几乎总是与单独的链接一起使用?