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.
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
But the power operator is double in both cases.
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.