【问题标题】:"Pseudo-" hash of 16-byte UUID16 字节 UUID 的“伪”哈希
【发布时间】:2021-01-11 02:10:31
【问题描述】:

我正在编写一个哈希表实现,它可以接受任意数据大小作为键和自定义哈希函数(返回 uint32_t)。

我有一个使用 16 字节 UUID 作为键的哈希表实例。由于 UUID 的分布已经非常广泛,我认为散列函数可以很简单

typedef unsigned char UUID[16];

static inline uint32_t uuid_hash_fn(const UUID uuid)
{ return *((uint32_t*)(uuid + 4)); }  // skipping the 4 MSB that are constant in UUID

这有什么问题吗?

函数是否已经被优化,因为它只需要足够的最左边字节来填充 uint32?

编辑:根据评论者的建议,我想澄清一下“这有什么问题吗”我的意思是:这种方法是否有可能出现意外行为?

【问题讨论】:

  • 这段代码有问题还是您只是在寻找“最佳实施”建议?
  • “最好最快”的实施建议。
  • @Abion47 如果尚未实施,则不会。
  • @MarkRansom 代码可能包含客观错误,但这不是问题所在。如果问题被改写为询问代码中是否存在错误或未定义的行为,而不是询问这是否已“优化”或此散列函数的“最佳实现”是什么,那么它将成为这里的主题。
  • @user3758232 如果基地址对齐,则 4 字节跳转与 uint32_t 对齐。鉴于uuid 只需要char 对齐,不确定uuid+4 是否与uint32_t 对齐。覆盖union 和其他对齐代码可能会解决这种极端情况。

标签: c hash


【解决方案1】:

这种方法是否有可能出现意外行为?

是的。代码具有 UB,因为 (uint32_t*)(uuid + 4) 依赖于 uuiduint32_t 访问对齐。 uuid 只需要 char 对齐。

UUID 已经有非常广泛的分布

嗯,也许不是。我会寻找整个对象的哈希值,并相信我的编译器会为memcpy() 发出有效的代码。

// Example that uses the entire UUID.
static inline uint32_t uuid_hash_fn(const UUID uuid) {
  uint32_t hash[4];
  memcpy(hash, &uuid, sizeof hash);
  return hash[0] ^ hash[1] ^ hash[2] ^ hash[3];
}

更好的哈希可能使用64-bit modulo 32-bit primelargest 32-bit prime

static inline uint32_t uuid_hash_fn(const UUID uuid) {
  uint64_t hash[2];
  memcpy(hash, &uuid, sizeof hash);
  return (hash[0] ^ hash[1])%4294967291u;
}

// skipping the 4 MSB that are constant in UUID 不清楚,因为代码尝试使用 16 个字节中的 4 个跳过 8 个 MSbytes。

【讨论】:

    【解决方案2】:

    您正在做的事情的基本思想(将现有的随机位回收为哈希)很好;只要您不需要加密安全的哈希(我怀疑)。

    关于对齐问题,另一个答案是正确的。要解决这个问题:

    a) 改用typedef uint32_t UUID[4];。对于所有代码,这可能会更好/更快,这意味着您可以return UUID[1]; 无需强制转换。进行此更改可能还需要更长的时间(取决于原始 UUID 的来源以及您在其他地方使用它的方式)

    b) 使用return (uint32_t)UUID[4] | ((uint32_t)UUID[5] << 8) | ((uint32_t)UUID[6] << 16) | ((uint32_t)UUID[7] << 24); 之类的东西,这样就不需要对齐了。这是一个简单的更改,但性能更差。

    【讨论】:

    • 我最喜欢这个答案,因为它解决了对齐问题,并且不假设加密散列对于散列表来说是“坏的”(=不必要的慢)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-22
    • 1970-01-01
    • 2021-11-22
    • 2018-04-24
    • 2012-03-26
    • 2017-06-07
    • 1970-01-01
    相关资源
    最近更新 更多