Как реализовать murmurhash3 в VBNET - PullRequest
0 голосов
/ 10 марта 2012

Я пытаюсь реализовать murmurhash3 в vb.net и пытаюсь конвертировать из этой C # реализации

первая часть функции в c #

public static SqlInt32 MurmurHash3(SqlBinary data)
{
const UInt32 c1 = 0xcc9e2d51;
const UInt32 c2 = 0x1b873593;

int curLength = data.Length;    /* Current position in byte array */
int length = curLength;   /* the const length we need to fix tail */
UInt32 h1 = seed;
UInt32 k1 = 0;

/* body, eat stream a 32-bit int at a time */
Int32 currentIndex = 0;
while (curLength >= 4)
{
  /* Get four bytes from the input into an UInt32 */
  k1 = (UInt32)(data[currentIndex++]
    | data[currentIndex++] << 8
    | data[currentIndex++] << 16
    | data[currentIndex++] << 24);

  /* bitmagic hash */
  k1 *= c1;
  k1 = rotl32(k1, 15);
  k1 *= c2;

  h1 ^= k1;
  h1 = rotl32(h1, 13);
  h1 = h1 * 5 + 0xe6546b64;
  curLength -= 4;
}

И то же самое в VB.net:

     Public Shared Function MurmurHash3(data As Byte()) As Int32
    Const c1 As UInt32 = &HCC9E2D51UI
    Const c2 As UInt32 = &H1B873593

    Dim curLength As Integer = data.Length
    ' Current position in byte array 
    Dim length As Integer = curLength
    ' the const length we need to fix tail 
    Dim h1 As UInt32 = seed
    Dim k1 As UInt32 = 0

    ' body, eat stream a 32-bit int at a time 
    Dim dBytes As Byte()
    Dim currentIndex As Int32 = 0
    While curLength >= 4
        ' Get four bytes from the input into an UInt32 
        dBytes = New Byte() {data(currentIndex), data(currentIndex + 1), data(currentIndex + 2), data(currentIndex + 3)}
        k1 = BitConverter.ToUInt32(dBytes, 0)

        currentIndex += 4
        ' bitmagic hash 

        k1 *= c1
        k1 = rotl32(k1, 15)
        k1 *= c2

        h1 = h1 Xor k1
        h1 = rotl32(h1, 13)
        h1 = h1 * 5 + &HE6546B64UI
        curLength -= 4
    End While

Private Shared Function rotl32(x As UInt32, r As Byte) As UInt32
    Return (x << r) Or (x >> (32 - r))
End Function

k1 * = c1 Выдает ошибку. Арифметическая операция вызвала переполнение.

Любые предложения, как это должно быть реализовано? Я не уверен, как сделать Get четыре байта из входных данных в часть UInt32, если это проблема или это связано с чем-то другим, поскольку есть некоторые различия в побитовых операциях между C # и VB.

Для справки также существует реализация Java https://github.com/yonik/java_util/blob/master/src/util/hash/MurmurHash3.java

Ответы [ 2 ]

1 голос
/ 07 февраля 2013

Сначала я бы преобразовал 32-битный k1 в 64-битный вариант, например:

k1_64 = CType(k1, UInt64)

для вычисления по модулю 32 бит, выполните

k1_64 = (k1_64 * c1) And &HFFFFFFFFUI

наконец, вернитесь к 32-битному

k1 = CType(k1_64 And $HFFFFFFFFUI, UInt32)

, чтобы повысить производительность. Возможно, вы захотите заменить вызов BitConverter.ToUInt чем-то другим.

EDIT: Вот более простая версия без дополнительной переменной (но с «вспомогательной константой»).

Const LOW_32 as UInt32 = &HFFFFFFFFUI
' ... intervening code ...
k1 = (1L * k1 * c1) And LOW_32
' ... later on ...
h1 = (h1 * 5L + &HE6546B64UL) And LOW_32

1L заставляет вычисление внутри паренсов выполняться как Long (Int64).And LOW_32 уменьшает количество ненулевых битов до 32, и затем общий результат автоматически преобразуется в UInt32.Аналогичная вещь происходит в строке h1.

Ссылка: http://www.undermyhat.org/blog/2009/08/secrets-and-lies-of-type-suffixes-in-c-and-vb-net/ (прокрутите вниз до раздела «Секреты констант и суффиксы типов»)

0 голосов
/ 12 марта 2012

К сожалению, возможно ли сделать эквивалент unchecked {} в VB.NET? Вы можете использовать блокировку try / catch и сделать сдвиг вручную, если вы переполнены. Только будьте осторожны, добавление обработчика ошибок замедлит вычисление хеша.

...