我在VS2010上使用stdext::hash_value()
尝试了一些散列算法,并实现了这一点:
#include <iostream>
#include <xhash>
using namespace std;
int main()
{
#ifdef _WIN64
std::cout << "x64" << std::endl;
#else
std::cout << "x32" << std::endl;
#endif
std::cout << stdext::hash_value(345.34533) << std::endl;
std::cout << stdext::hash_value(345.566) << std::endl;
return 0;
}
// Output is:
// x64
//3735928758
//3735928758
我尝试了一些其他具有相同整数但不同小数部分的双变量对。喜欢1.234 vs 1.568。哈希值始终相同。所以我看一下hash_value()
的来源并看到了
#define _HASH_SEED (size_t)0xdeadbeef
template<class _Kty> inline
size_t hash_value(const _Kty& _Keyval)
{ // hash _Keyval to size_t value one-to-one
return ((size_t)_Keyval ^ _HASH_SEED);
}
_KeyVal
被投射到size_t
,这对我没有意义。该函数只是忽略double的小数部分。这种实施背后的逻辑是什么?这是一个错误或功能吗?
答案 0 :(得分:2)
stdext :: hash_value不是哈希函数。它是哈希函数的输入,您将它专门用于您的类型,以便它可以用作stdext哈希类的键。但是,它似乎没有任何文件。实际的哈希函数是stdext :: hash_compare。
但是因为没有hash_value的默认特化,所以它使用convert-to-int方法忽略小数部分。
在vc10之前,标准的std :: tr1 :: hash / std :: hash函数有一个几乎完全相同的错误:
在vc10中,std :: hash得到一个哈希位的双重特化。我想stdext现在已经过时了,所以即使在vc10中也没有解决它。
答案 1 :(得分:1)
编写该函数以使用任何类型的数据。它没有对大小做出假设,因此对某些类型来说效率低下。您可以为双精度覆盖此行为,以通过模板专业化提高效率
template<>
size_t hash_value<double>(const double& key) {
return // Some awesome double hashing algorithm
}
将此定义置于main
方法之上将导致对stdext::hash_value(354.566)
的调用绑定到此定义,而不是标准
答案 2 :(得分:0)
这是旧代码 - 似乎不太好。
您应该尝试使用std :: hash。
答案 3 :(得分:0)
显然,这是尝试为其提供通用散列函数 整数(虽然我不知道xor添加了什么)。很清楚 不适用于大多数其他类型。包括浮点。
为浮点值提供良好的散列函数是困难的; 如果我试图制作通用哈希,我可能会从测试开始 对于0,NaN和Inf,并返回那些(或 完全拒绝NaN,因为它不是有效的哈希值),然后 只需在底层字节上使用标准字符串哈希。这将 至少使哈希与==运算符兼容。但问题 精度意味着==本身可能不是所需要的。也不是 std :: map的情况,因为std :: map使用&lt;定义一个平等 关系,并根据浮动或双打的来源,如此 等式关系可能不适合哈希表。
无论如何,不要期望为浮点类型找到标准哈希函数。
答案 4 :(得分:0)
VC10包含C ++ 0x标准散列机制,因此不再需要使用stdext
,std::hash
确实包含执行按位转换的double
机制然后是哈希。您拥有stdext
的代码只是一种回退机制,并不适合用于浮点类型。我想这是一个设计疏忽。
template<>
class hash<double>
: public unary_function<double, size_t>
{ // hash functor
public:
typedef double _Kty;
typedef _ULonglong _Inttype; // use first 2*32 bits
size_t operator()(const _Kty& _Keyval) const
{ // hash _Keyval to size_t value by pseudorandomizing transform
_Inttype _Bits = *(_Inttype *)&_Keyval;
return (hash<_Inttype>()(
(_Bits & (_ULLONG_MAX >> 1)) == 0 ? 0 : _Bits));
}
};