寻找无符号整数的双射函数,将序列0,...,n均匀映射到图像上

时间:2016-05-08 00:31:49

标签: c++ algorithm hash integer

我正在尝试找到一个(哈希)函数,该函数采用32位或64位的无符号整数,并将其再次映射到同一类型。

它应该是双射的,快速的。

附加财产:

对于任何n,应将0到n的序列“均匀”映射到图像上。 意思是,如果我将图像分成k个相同大的子集,它们应该大致相等,因为k <&lt;&lt; Ñ

3 个答案:

答案 0 :(得分:0)

  

我正在尝试找到一个(哈希)函数,该函数采用32位或64位的无符号整数,并将其再次映射到同一类型。

     

它应该是双射的,快速的。

嗯,满足0碰撞的函数是身份函数,即

uint64_t hash(uint64_t inp) {
    return inp;
}

您的其他属性:

  

对于任何n,应将0到n的序列“均匀”映射到图像上。

嗯,所以身份不会这样做,因为前n个数字当然是紧凑的。但是:

位反转可以解决问题!

因此,不要返回相同的数字,只需返回它们的位反转版本。

位反转通常不是快速操作,除非你有技巧和/或CPU指令可以帮助你。

编辑:啊等等,我记得Knuth已经提出了一个功能,它应该比你的平均哈希impl快得多。

答案 1 :(得分:0)

假设mult是奇数(T的范围是2的幂,就像在任何现代处理器上一样),

返回的任何函数
template <T>
auto linear_congruential_hash(T mult, T incr) {
    static_assert(std::is_integral<T>::value,
                  "template argument must be an integral type");
    return [mult, incr](T n) -> T {
        return mult * n + incr;
    }
}

是双射的。如果mult接近T的上限,那么函数也将接近满足您的一致性要求(只是避免使mult使得它的一些小的倍数太接近为0,例如0x7fffffffU会很糟糕)。所以,举一个具体的例子,像linear_congruential_hash<uint32_t>(0x68832099U, 0x30571005U)这样的东西应该可以很好地运作。

答案 2 :(得分:-1)

这符合您的所有要求:

unsigned int identity(unsigned int x) {
    return x;
}