同时在多个字节上的SDBM哈希

sdbm hash on multiple bytes simultaneously

本文关键字:SDBM 哈希 字节      更新时间:2023-10-16

这是用于字节字符串的SDBM哈希算法的代码...

unsigned long sdbm(unsigned char *key, int bytes)
{
    unsigned long hash = 0;
    unsigned char *end = key + bytes;
    while (key < end) hash = (unsigned long)(*key++) + (hash << 6) + (hash << 16) - hash;
    return hash;
}

现在假设所有传递给SDBM()的字符串都是4个字节。有什么方法可以一次计算所有四个字节的SDBM哈希,而将字符串视为32位的无符号值?我有此代码,假设字符串键为4个字节

#define SUBHASH(x) ((x << 6) + (x << 16) - x)
unsigned long sdbm4(unsigned long key)
{
    unsigned long hash = (key & 0xFF);
    hash = ((key & 0xFF00) >> 8) + SUBHASH(hash);
    hash = ((key & 0xFF0000) >> 16) + SUBHASH(hash);
    return  (key >> 24) + SUBHASH(hash);
}
char *tmp = "test";
int main(void)
{
    unsigned long a = sdbm((unsigned char *)tmp, 4);
    unsigned long b = sdbm4(*(unsigned long *)tmp);
    printf("a = %lu, b = %lun", a, b);
    while (!_kbhit());
    return 0;
}

运行此功能将揭示两个函数都计算相同的值,而SDBM4()专门用于处理4个字节字符串。没有循环,没有测试,并且堆栈上的值立即初始化为第一个值。但是,如果有一种方法可以将其凝结成一个陈述而不是四个陈述,那就太好了。那可能吗?我认为Simd可能可以做到,但是我不确定如何或是否有任何好处。

显然可以完成,您只需要四次扩展语句内联。您对Subhash的定义如果通过表达式,将破坏它,因此我们必须修复它 - 因此我们不妨使其成为内联函数。

inline constexpr unsigned long SubHash(unsigned long x) {
    return ((x << 6) + (x << 16) - x);
}

inline constexpr unsigned long sdbm4(unsigned long key)
{
    return  (key >> 24) + 
                SubHash(((key & 0xFF0000) >> 16) + 
                    SubHash(((key & 0xFF00) >> 8) + 
                        SubHash(key & 0xFF))));
}

如果值得,我会感到非常惊讶。该规则始终是首先编写代码,并且只有分析显示出存在问题时才开始优化。(请注意,关于瓶颈可能在哪里的本能几乎总是错误的。)

如果您确实要使用#Define,则需要将其更改为:

#define SUBHASH(x) (((x) << 6) + ((x) << 16) - (x))

您可能会发现生成的代码是相同的。