Java和C ++之间的Murmurhash3没有对齐

时间:2014-06-06 19:59:04

标签: java c++ murmurhash

我有两个独立的应用程序,一个是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的一个:http://search-hadoop.com/c/HBase:hbase-common/src/main/java/org/apache/hadoop/hbase/util/MurmurHash3.java||server+void+%2522hash

上面有相同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 ++中匹配。

赞赏任何指针

2 个答案:

答案 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生成相同的哈希值。