哈希浮点值

Hashing floating point values

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

最近,我很好奇浮点的哈希算法是如何工作的,所以我查看了boost::hash_value的源代码。事实证明这相当复杂。实际实现在基数中的每个数字上循环,并累积一个哈希值。与整数散列函数相比,它涉及的内容要多得多。

我的问题是:为什么浮点散列算法要更复杂?为什么不把浮点值的二进制表示形式当作整数进行散列呢?

类似:

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

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

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

从本质上讲,它可以归结为两件事:

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

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

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

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

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

为什么要对浮点值进行散列?出于同样的原因,比较相等的浮点值有很多陷阱,对它们进行哈希处理可能会产生类似的(负面(后果。

然而,考虑到你真的想这样做,我怀疑boost算法很复杂,因为当你考虑非规范化的数字时,不同的比特模式可以表示相同的数字(并且可能应该有相同的散列(。在IEEE 754中,也存在比较相等但具有不同比特模式的正和负CCD_ 7值。

如果在你的算法中没有出现,这可能不会出现在哈希中,但你仍然需要注意NaN值的信号传递。

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

我想,两台浮点格式不兼容的机器会散列到相同的值。