代码之家  ›  专栏  ›  技术社区  ›  Xavier Junqué

可能的VB.NET错误:位移位和幂运算符的行为不一致

  •  1
  • Xavier Junqué  · 技术社区  · 7 月前

    我在VB.NET中遇到了一个意外的行为,这可能是一个错误,或者至少是处理类型和操作的方式不一致。以下示例说明了该问题:

    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
    

    事情是这样的:

    k1是奇数。
    k3被计算为k2<<47,这是位移位,工作正常。
    k4是使用k1-k2*(2L^47)计算的。
    结果在逻辑上也应该是奇数,因为k1和k3都按预期对齐。然而,结果是偶数。
    问题似乎在于表达式(2L^47)。在VB.NET中,^运算符是幂运算符,而不是许多其他语言中的位XOR。这会导致计算过程中出现意外的类型转换和舍入误差。

    为什么在C#中不会发生这种情况?
    在C#中,幂没有^运算符(它明确用于XOR)。功率计算需要调用Math。Pow或类似的方法,避免这种歧义。

    还有其他人遇到过这个问题吗?这感觉就像VB.NET中的设计疏忽,因为这种不一致很容易导致微妙的错误。

    2 回复  |  直到 7 月前
        1
  •  2
  •   djv    7 月前

    分解各个操作,它是奇怪的/正确的(?)

    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 现在。

    我猜其中一个嵌套操作被视为double,因此存在舍入问题。

    是的,乘法被视为双倍

    独处时,它不是

    enter image description here

    但在这两种情况下,电力运营商都是双重的。

    enter image description here

    无论它如何工作,当你分配正确的double结果时 ^ 变成一个长变量。但是,如果你不将其赋值给一个长变量,它就会在嵌套操作中浮动,从而导致 * 操作符是双版本,就在双版本之后 ^ 。由于你没有分配一个长任务,错误就会累积,结果就是错误的。

        2
  •  0
  •   dbasnett    7 月前

    VB中的XOR运算符,

        Dim k4 As Int64 = k1 - k2 * (2L Xor 47)