我有两个独立的应用程序,一个是Java,另一个是C ++。我正在使用Murmurhash3。但是,在C ++中,与Java相比,我获得了与相同字符串
不同的结果以下是C ++中的一个:https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp?r=144
我正在使用以下功能:
void MurmurHash3_x86_32 ( const void * key, int len,
uint32_t seed, void * out )
上面有相同Java代码的许多版本。
这就是我打电话给Java的方式:
String s = new String("b2622f5e1310a0aa14b7f957fe4246fa");
System.out.println(MurmurHash3.murmurhash3_x86_32(s.getBytes(), 0, s.length(), 2147368987));
我从Java获得的输出: -1868221715
我从C ++获得的输出 3297211900
当我测试一些其他样本字符串时 “7c6c5be91430a56187060e06fd64dcb8”和“7e7e5f2613d0a2a8c591f101fe8c7351”在Java和C ++中匹配。
赞赏任何指针
答案 0 :(得分:1)
我可以看到两个问题。首先,C ++使用uint32_t
,并给你一个3,297,211,900的值。这个数字大于有符号的32位int,Java只使用有符号整数。但是,-1,868,221,715不等于3,297,211,900,甚至考虑了有符号和无符号整数之间的差异。
(在Java 8中,他们添加了Integer.toUnsignedString(int)
,它将签名的32位int转换为其无符号字符串表示。在早期版本的Java中,您可以将int
强制转换为{{ 1}}然后屏蔽高位:long
。)
第二个问题是您使用的是((long) i) & 0xffffffffL
的错误版本。不带参数的那个使用默认平台编码将Unicode getBytes()
转换为String
,这可能会根据您的系统设置方式而有所不同。它可以给你UTF-8,Latin1,Windows-1252,KOI8-R,Shift-JIS,EBCDIC等。
永远不会在任何情况下调用byte[]
的无参数版本。它应该被弃用,抽取,删除,销毁和删除。
使用String.getBytes()
(或您期望得到的任何编码)。
正如 Python的所说的那样,“明确比隐含更好。”
我不知道这两者之外是否还有其他问题。
答案 1 :(得分:1)
我遇到了同样的问题。但是我的Murmurhash3的Java版本与你的不同。在对Murmurhash3的C ++版本进行一些更改之后,我将从两个版本生成的哈希值相同。我给你我的解决方案,你可以用它来检查它是否也适合你。
也许Java和C ++版本之间的最大区别在于右移操作(在Java中你可以看到>>和>>>,而在C ++中,您只能看到>>)。 Java中的整数都是有符号的,而在C ++中,您可以使用有符号或无符号整数。在Java版本中,>> 表示算术右移,>>> 表示逻辑右移。在C ++中,>> 表示算术右移。 Murmurhash3的原始C ++版本使用无符号整数,并且为了在Java中生成负散列值,在C ++中 first ,您应该将所有无符号类型 uint32_t 更改为已签名输入 int32_t 。 然后您应该在Java中找到>>> ,并在C ++中围绕相应的>> 进行更改。对我来说,我改变了:
inline uint32_t rotl32 ( uint32_t x, int8_t r )
{
return (x << r) | (x >> (32 - r));
}
以强>
inline int32_t rotl32 ( int32_t x, int8_t r )
{
return (x << r) | (int32_t)((uint32_t)x >> (32 - r)); //similar to >>> in Java
}
来自:
FORCE_INLINE uint32_t fmix32 ( uint32_t h )
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
以强>
FORCE_INLINE int32_t fmix32 ( int32_t h )
{
h ^= (int32_t)((uint32_t)h >> 16); // similar to >>> in Java
h *= 0x85ebca6b;
h ^= (int32_t)((uint32_t)h >> 13);
h *= 0xc2b2ae35;
h ^= (int32_t)((uint32_t)h >> 16);
return h;
}
通过这种方式,我在Java和C ++中的两个版本的Murmurhash3生成相同的哈希值。