【问题标题】:Hashing floating point values散列浮点值
【发布时间】:2011-11-16 05:19:39
【问题描述】:

最近,我很好奇浮点哈希算法是如何工作的,所以我查看了boost::hash_value 的源代码。原来是fairly complicated。实际的实现循环遍历基数中的每个数字并累积一个哈希值。与整数散列函数相比,它涉及更多。

我的问题是:为什么浮点哈希算法应该更复杂?为什么不直接对浮点值的二进制表示进行散列,就好像它是一个整数一样?

喜欢:

std::size_t hash_value(float f)
{
  return hash_value(*(reinterpret_cast<int*>(&f)));
}

我意识到float 不能保证在所有系统上都与int 大小相同,但是可以使用一些模板元程序来处理这种事情,以推导出一个大小相同的整数类型作为float。那么引入一个完全不同的专门对浮点类型进行操作的哈希函数有什么好处呢?

【问题讨论】:

  • 正如所写,您违反了严格的别名规则(如果intfloat 的大小不同,则更糟),但我很想知道将其转换为给定长度的char*
  • Hash function for floats的可能重复

标签: c++ hash floating-point


【解决方案1】:

我想这是因为两台具有不兼容浮点格式的机器哈希到相同的值。

【讨论】:

  • 假设我只想在 std::unordered_set 中使用浮点数,没有理由在机器之间共享哈希值。
【解决方案2】:

不只使用位模式的一个原因是一些不同的位模式必须被认为是相等的,因此具有相同的哈希码,即

  • 正负零
  • 可能是非规范化数字(我认为 IEEE 754 不会发生这种情况,但 C 允许其他浮点表示)。
  • 可能是 NAN(有很多,至少在 IEEE 754 中。它实际上要求将 NAN 模式视为与自身不相等,这可能意味着不能在哈希表中有意义地使用)

【讨论】:

  • 为什么 NAN 必须被认为是平等的? NAN != NAN.
  • 实际上,我收回了这一点。该标准规定“对 h(k) 表达式的所有评估,对于 k 具有相同的值会产生相同的结果。”不是(如我所料),“所有评估h(k)h(l) 其中k == l 产生相同的结果”。因此,根据哈希要求,== 的相关性低于“相同的值”。两个不同的 NAN 是否是“相同的值”是一个标准梳理练习,我不介意:-)
  • 即使NaN != NaN,哈希函数也被视为黑盒;也就是说,散列值的消费者(例如关联容器)不会提供不可比性。因此,要么hash(NaN) == hash(NaN) 必须为真,要么数据类型不应该是可散列的。
【解决方案3】:

为什么要散列浮点值?出于同样的原因,比较浮点值是否相等有许多陷阱,散列它们可能会产生类似的(负面)后果。

但是,鉴于您确实想要这样做,我怀疑 boost 算法很复杂,因为当您考虑非规范化数字时,不同的位模式可以表示相同的数字(并且可能应该具有相同的哈希)。在 IEEE 754 中,也有正负 0 值,它们比较相等但具有不同的位模式。

如果它不会在您的算法中出现,那么它可能不会出现在散列中,但您仍然需要注意信号 NaN 值。

此外,散列 +/- 无穷大和/或 NaN 的含义是什么?具体来说,NaN 可以有很多表示,它们是否都应该产生相同的哈希? Infinity 似乎只有两种表示形式,所以它似乎可以正常工作。

【讨论】:

  • 您能否详细说明为什么您认为散列 +/- 无穷大和 NaN 没有意义?我不明白为什么这可能是一个问题。
  • 至少对于 IEEE 754,我不认为由于非规范化而具有相同值的不同模式
  • @Michael Borgwardt 当然 +/- 0 和各种 NaN 值可能出现在 IEEE 754 中。不过我不确定其他值。
  • 除非标准另有说明,否则我希望 +/- inf 被视为该类型的任何其他值 - 理想情况下它们应该具有不同的哈希值。如果您的浮点类型中有两种 +inf 表示,则它们必须具有相同的哈希值。
  • 不错的答案,除了毫无意义的“你为什么要这样做?”。有用例。只是因为你想不到他们……
【解决方案4】:

看看https://svn.boost.org/trac/boost/ticket/4038

本质上归结为两件事:

  • 可移植性:当您采用浮点数的二进制表示时,在某些平台上,具有相同值的浮点数可能有多种二进制表示。我不知道是否真的有一个平台存在这样的问题,但是由于去规范化数字的复杂性,我不确定这是否真的会发生。

  • 第二个问题就是你提出的,可能sizeof(float)不等于sizeof(int)

我没有发现有人提到 boost hash 确实避免了更少的冲突。虽然我认为将尾数与指数分开可能会有所帮助,但上述链接并不表明这是驱动设计决策。

【讨论】:

    猜你喜欢
    • 2011-05-13
    • 1970-01-01
    • 2018-11-27
    • 2019-11-29
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 2021-01-11
    相关资源
    最近更新 更多