std::hash 是否保证"equal"浮点数的哈希值相等?
Does std::hash guarantee equal hashes for "equal" floating point numbers?
关于几乎相等,std::hash
的浮点专业化(例如,对于double
s或float
s)是否可靠?也就是说,如果两个值(如(1./std::sqrt(5.)/std::sqrt(5.))
和.2
)应该比较相等,但==
运算符不会这样做,那么std::hash
将如何表现?
那么,我可以依靠double
作为std::unordered_map
密钥来按预期工作吗?
我看过"哈希浮点值",但这是关于提升的问题;我在问关于C++11的保证。
std::hash
对所有类型都有相同的保证被实例化:如果两个对象相等,它们的哈希代码将平等。否则,他们很有可能不会。因此,您可以将double
作为unordered_map
按预期工作:如果没有两个替身相等(如==
所定义),它们可能会有不同的hash(即使它们不是,它们也是不同的密钥,因为unordered_map
也检查相等性)。
显然,如果你的价值观是不精确的结果计算,它们不适合unordered_map
(也许对于任何地图来说都是如此)。
此问题存在多个问题:
-
你的两个表达式不相等的原因不是有两个0.2的二进制表达式,而是没有
0.2
或sqrt(5)
的精确(有限)二进制表示!因此,事实上,虽然(1./std::sqrt(5.)/std::sqrt(5.))
和.2
在代数上应该是相同的,但在计算机精度算术中它们很可能不相同。(它们甚至不是有限精度的纸上算术。假设你正在使用小数点后的10位数字。用10位数字写出sqrt(5)
,然后计算你的第一个表达式。它不会是.2
。) -
当然,你有一个合理的概念,两个数字是接近的。事实上,你至少有两个:一个绝对值(
|a-b| < eps
),一个相对值。但这并不能转化为合理的话题。如果您希望eps
中的所有数字都具有相同的哈希,那么1, 1+eps, 1+2*eps, ...
将具有相同的hash,因此,所有数字都将具有相同哈希。这是一个有效但无用的散列函数。但它是唯一一个满足您将附近值映射到同一哈希的要求的!
在unordered_map
的默认哈希后面有一个std::hash
结构,它提供operator()
来计算给定值的哈希。
此模板的一组默认专业化可用,包括std::hash<float>
和std::hash<double>
。
在我的机器上(LLVM+clang),这些被定义为
template <>
struct hash<float> : public __scalar_hash<float>
{
size_t operator()(float __v) const _NOEXCEPT
{
// -0.0 and 0.0 should return same hash
if (__v == 0)
return 0;
return __scalar_hash<float>::operator()(__v);
}
};
其中__scalar_hash
定义为:
template <class _Tp>
struct __scalar_hash<_Tp, 0> : public unary_function<_Tp, size_t>
{
size_t operator()(_Tp __v) const _NOEXCEPT
{
union
{
_Tp __t;
size_t __a;
} __u;
__u.__a = 0;
__u.__t = __v;
return __u.__a;
}
};
基本上,散列是通过将并集的值设置为源值,然后只获得一个大到size_t
的片段来构建的。
所以你得到了一些填充或截断了你的值,但这并不重要,因为正如你所看到的,数字的原始位被用来计算哈希,这意味着它与==
运算符完全一样。两个浮点数要具有相同的散列(不包括截断引起的冲突),必须是相同的值。
没有严格的"几乎相等"概念。因此,行为原则上不能得到保证。如果你想定义你自己的"几乎相等"概念,并构造一个散列函数,使两个"几乎相等的"浮点具有相同的散列,你可以。但只有当你认为"几乎相等"的浮动时,这才是真的。
- boost::包含提升单元的元组的哈希值
- 如何使用 STL 哈希容器中的哈希值检索元素?
- 哈希函数中同一键的不同值和良好的哈希值排序
- 字符串单词的唯一哈希值
- 是否可以将哈希值作为编译时常数
- CMake检查下载文件的哈希值(MD5/SHA256)
- 正在将哈希值存储到int
- 如何计算没有标签信息的 mp3 文件的哈希值
- 如何定义函数序列的哈希值(C++)
- C++-对象图的哈希值类似于boost::序列化
- 如何获取哈希值,C++ hash_map
- 在Qt中创建目录的哈希值
- 杂音哈希 - 哈希值不一致
- 逐行散列文件时错误的 md5 哈希值
- 为什么不同程序执行之间的哈希值不一致
- 如何有效地存储和排序生日攻击的哈希值
- unordered_map存储桶中的所有元素是否具有相同的哈希值
- 使用openssl/MD5时出现意外的MD5哈希值
- 存储具有字符串类型键的哈希值的最佳结构
- std::hash 是否保证"equal"浮点数的哈希值相等?