2

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)"

Community
  • 1
  • 1
Artem
  • 1,000
  • 1
  • 15
  • 30

2 Answers2

4

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 :)

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Is there no way to change overflow checking for a single file/part of a file in VB.net? Similar to the C# `unchecked` keyword? – CodesInChaos Mar 17 '12 at 16:22
  • No, there's no keyword for it in the language. There can't be, overflow checking is assumed by the language syntax. Which is why you don't have to cast to assign an int to a byte. – Hans Passant Mar 17 '12 at 16:44
0

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.

Darryl
  • 5,907
  • 1
  • 25
  • 36