Murmurhash3 между Java и C ++ не выравнивает

У меня есть 2 отдельных приложения, одно на 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 ++.

Любые указатели приветствуются

0

Решение

Я вижу две проблемы. Во-первых, 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 к long а затем замаскировать старшие биты: ((long) i) & 0xffffffffL.)

Вторая проблема заключается в том, что вы используете неправильную версию getBytes(), Тот, который не принимает аргументов, преобразует Unicode String к byte[] используя кодировку платформы по умолчанию, которая может варьироваться в зависимости от того, как настроена ваша система. Это может дать вам UTF-8, Latin1, Windows-1252, KOI8-R, Shift-JIS, EBCDIC и т. Д.

Никогда, никогда не называй версию без аргументов String.getBytes(), при любых обстоятельствах. Он должен быть устаревшим, уничтожен, удален, уничтожен и удален.

использование s.getBytes("UTF-8") (или любую другую кодировку, которую вы ожидаете получить).

Как Дзен питона говорит: «Явное лучше, чем неявное».

Я не могу сказать, могут ли быть какие-либо другие проблемы кроме этих двух.

1

Другие решения

У меня была такая же проблема с тобой. Но Java-версия моего Murmurhash3 отличается от вашей. После внесения некоторых изменений в версию Murmurhash3 для C ++ я сделал одинаковыми значения хеш-функции, сгенерированные из двух версий. Я даю вам свое решение, которое вы можете использовать, чтобы проверить, работает ли оно и на вас.

Возможно, самая большая разница между версиями Java и C ++ заключается в операция правого сдвига (в Java вы можете видеть >> и >>>, в то время как в C ++ вы можете видеть только >>). Целые числа в Java все подписаны, в то время как в C ++ вы можете использовать целые числа со знаком или без знака. В версии Java >> означает арифметическое смещение вправо и >>> означает логический сдвиг вправо. И в C ++ >> означает арифметическое смещение вправо. Исходная версия Murmurhash3 для C ++ использует целое число без знака, и для генерации отрицательного значения хеша, как в Java, первый в C ++ вы должны поменять все типы без знака 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;
}

Таким образом, две мои версии Murmurhash3 на Java и C ++ генерируют одинаковое хеш-значение.

1

По вопросам рекламы [email protected]