简体   繁体   中英

How to implement GetStableHash method in VB.NET

I've already asked this question on several forums, but without any good explanation of why the code above cannot be converted from C# to Visual Basic.

The code is actually from this forum, written in C#. (the source)

static public int GetStableHash(string s)
       {
           uint hash = 0;
            // if you care this can be done much faster with unsafe 
            // using fixed char* reinterpreted as a byte*
            foreach (byte b in System.Text.Encoding.Unicode.GetBytes(s))
            {

                hash += b;
                hash += (hash << 10);
                hash ^= (hash >> 6);

            }
            // final avalanche
            hash += (hash << 3);
            hash ^= (hash >> 11);
            hash += (hash << 15);
            // helpfully we only want positive integer < MUST_BE_LESS_THAN
            // so simple truncate cast is ok if not perfect
            return (int)(hash % MUST_BE_LESS_THAN);
       }

So, the code ought to be something like that in VB.NET

    Const MUST_BE_LESS_THAN As Integer = 100000000

Function GetStableHash(ByVal s As String) As Integer


    Dim hash As UInteger = 0

    For Each b as Byte In System.Text.Encoding.Unicode.GetBytes(s)
        hash += b
        hash += (hash << 10)
        hash = hash Xor (hash >> 6)
    Next

    hash += (hash << 3)
    hash = hash Xor (hash >> 11)
    hash += (hash << 15)

    Return Int(hash Mod MUST_BE_LESS_THAN)
End Function

It seems to be right, but it does not work. In VB.NET, there is an overflow at "hash += (hash << 10)"

Overflow checking is off by default in C# but on by default in VB.NET. Project + Properties, Compile tab, scroll down, Advanced Compile Options and tick the "Remove integer overflow checks" option.

If that makes you uncomfortable then move the code into a separate class library project so the setting change doesn't affect the rest of your code. That other project could now also be a C# project :)

As Hans explained, you are getting an error because VB is doing overflow checking and C# is not. Without overflow checking, any extra bits are simply thrown away. You can replicate this same behavior by using a larger data type during the calculation and throwing the extra bits away manually. It takes 1 extra line of code, or 3 extra lines of code if you want the answers to match C# exactly (look for the comments):

Public Shared Function GetStableHash(ByVal s As String) As Integer

  ' Use a 64-bit integer instead of 32-bit
  Dim hash As ULong = 0

  For Each b As Byte In System.Text.Encoding.Unicode.GetBytes(s)
     hash += b
     hash += (hash << 10)
     ' Throw away all bits beyond what a UInteger can store
     hash = hash And UInteger.MaxValue
     hash = hash Xor (hash >> 6)
  Next

  hash += (hash << 3)
  ' Throw away all extra bits
  hash = hash And UInteger.MaxValue
  hash = hash Xor (hash >> 11)
  hash += (hash << 15)
  ' Throw away all extra bits
  hash = hash And UInteger.MaxValue

  Return Int(hash Mod MUST_BE_LESS_THAN)
End Function

If you are OK with slightly different results (but equally valid) from what the C# code produces, the only extra line of code you need is the one inside the For Each loop. You can delete the other two.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM