最近,我很好奇浮点数的哈希算法是如何工作的,所以我查看了boost::hash_value
的源代码。事实证明是fairly complicated。实际实现循环遍历基数中的每个数字并累积哈希值。与整数散列函数相比,它涉及更多。
我的问题是:为什么浮点哈希算法会更复杂?为什么不将浮点值的二进制表示形式哈希,就好像它是一个整数?
像:
std::size_t hash_value(float f)
{
return hash_value(*(reinterpret_cast<int*>(&f)));
}
我意识到float
并不能保证与所有系统上的int
大小相同,但是可以使用一些模板元程序来处理这种事情,以推断出一个整数类型与float
的大小相同。那么引入一个专门针对浮点类型操作的完全不同的哈希函数有什么好处呢?
答案 0 :(得分:5)
查看https://svn.boost.org/trac/boost/ticket/4038
从本质上讲,它归结为两件事:
可移植性:当你获取float的二进制表示时,那么在某个平台上,具有相同值的float可能有多个二进制表示。我不知道是否存在存在这样一个问题的平台,但由于解密数字的复杂性,我不确定这是否真的会发生。
第二个问题是您提出的问题,sizeof(float)
可能不等于sizeof(int)
。
我没有发现任何人提到增强哈希确实避免了更少的冲突。虽然我认为将尾数与指数分开可能会有所帮助,但上述链接并不表明这是驱动设计决策。
答案 1 :(得分:5)
不使用位模式的一个原因是必须将某些不同的位模式视为等于,因此具有相同的哈希码,即
答案 2 :(得分:4)
为什么要散列浮点值?出于同样的原因,比较浮点值的相等性存在许多缺陷,散列它们可能会产生类似(负面)的后果。
然而,鉴于你确实想要这样做,我怀疑升压算法很复杂,因为当你考虑非规范化数字时,不同的位模式可以表示相同的数字(并且应该具有相同的散列)。在IEEE 754中,还有正和负0
值,它们相等但有不同的位模式。
如果在你的算法中不会出现这种情况,这可能不会出现在散列中,但是你仍然需要注意信号NaN值。
此外,散列+/-无穷大和/或NaN的含义是什么?特别是NaN可以有很多表示,如果它们都导致相同的哈希?无限似乎只有两个表示,所以看起来好像可以。
答案 3 :(得分:0)
我想这是两台具有不兼容浮点格式的机器散列到相同的值。