vb.net

Possible VB.NET Bug: Inconsistent Behavior with Bitwise Shifts and Power Operator


I’ve come across an unexpected behavior in VB.NET, which might be a bug or at least an inconsistency in how types and operations are handled. The following example illustrates the issue:

Module Program
    Sub Main(args As String())
        Dim k1 As Int64 = 15368209579545345L ' odd number
        Dim k2 As Int64 = 109L
        Dim k3 As Int64 = k2 << 47
        Dim k4 As Int64 = k1 - k2 * (2L ^ 47)

        Console.WriteLine($"k1={k1}")
        Console.WriteLine($"k2={k2}")
        Console.WriteLine($"k3={k3}") ' Outputs: 15340386230730752 
        Console.WriteLine($"k4= k1 - k3 = {k4}") ' Outputs: 27823348814592, which is an even number
        Console.WriteLine($"k4= k1 - k3 should be: {15368209579545345L - 15340386230730752L}")
        Console.ReadLine()
    End Sub
End Module

Here’s what’s happening:

k1 is an odd number.
k3 is calculated as k2 << 47, which is a bitwise shift and works correctly.
k4 is calculated using k1 - k2 * (2L ^ 47).
The result should logically also be an odd number, as both k1 and k3 are aligned as expected. However, the result is an even number.
The issue seems to lie in the expression (2L ^ 47). In VB.NET, the ^ operator is a power operator, not a bitwise XOR as in many other languages. This leads to unexpected type conversions and rounding errors during calculation.

Why doesn’t this happen in C#?
In C#, there’s no ^ operator for power (it’s explicitly used for XOR). Power calculations require calling Math.Pow or similar methods, avoiding this kind of ambiguity.

Has anyone else encountered this issue? It feels like a design oversight in VB.NET, as such inconsistencies can easily lead to subtle bugs.


Solution

  • Break out the individual operations, and it's odd / correct(?)

    Dim k1 As Long = 15368209579545345L ' odd number
    Dim k2 As Long = 109L
    Dim k3 As Long = k2 << 47
    Dim k4 As Long = 2L ^ 47L
    Dim k5 As Long = k2 * k4
    Dim k6 As Long = k1 - k5
    
    Console.WriteLine($"k1={k1}")
    Console.WriteLine($"k2={k2}")
    Console.WriteLine($"k3={k3}")
    Console.WriteLine($"k4={k4}")
    Console.WriteLine($"k5={k5}")
    Console.WriteLine($"k6={k6}")
    

    k1=15368209579545345
    k2=109
    k3=15340386230730752
    k4=140737488355328
    k5=15340386230730752
    k6=27823348814593

    k3 = k5 now.

    I'm guessing one of those operations when nested is being treated as double, hence the rounding issue.

    Yes, the multiplication is treated as double

    When alone, it is not

    enter image description here

    But the power operator is double in both cases.

    enter image description here

    However it works, as you assign the correct result of the double ^ into a long variable. But if you don't assign it to a long variable, it's left floating in the nested operation, which results in the * operator being the double version, right after the double ^. Since you haven't assigned to a long, the errors build up, and the result is wrong.