【问题标题】:OverflowException only in VB.net, not in C#OverflowException 仅在 VB.net 中,不在 C# 中
【发布时间】:2016-03-30 14:01:51
【问题描述】:

出于自我教育的目的,我试图找到一种自己创建高度图的方法。 我google了一下,找到了一个创建伪随机数的函数。

    public static float Noise(int x)
    {
        x = (x << 13) ^ x;

        return (1f - ((x * (x * x * 15731 + 789221) + 1376312589) & 0x7FFFFFFF) / 1073741824.0f);
    }

由于我选择的语言是 VB.net,我将此函数翻译为:

Private Function Noise(ByVal x As Integer) As Double
    x = (x << 13) Xor x

    Return (1.0R - ((x * (x * x * 15731.0R + 789221.0R) + 1376312589.0R) And &H7FFFFFFF) / 1073741824.0R)
End Function

如果我使用 C# 版本,我会得到从 1 到 100 的 x 值的结果。如果我使用 VB.net 版本,我会得到 xOverFlowException。当我反汇编这个函数的部分时,我发现溢出的部分是

(x * x * 15731.0R)

所以,我的第一个问题是:为什么我在 VB.net 中得到 OverflowException 而在 C# 中却没有?如果中间结果对于它的包含变量来说太大了,无论我使用什么语言,它都应该太大了。

我的第二个问题是:我该怎么做才能让它在 VB.net 中也能正常工作?

感谢您的回答。

【问题讨论】:

    标签: c# vb.net


    【解决方案1】:

    为什么我在 VB.net 中得到 OverflowException 而在 C# 中却没有?

    因为 VB 项目默认会检查溢出,而 C# 不会。如果您将项目设置为检查溢出或将代码放在 checked{ } 块中,您会在 C# 中看到相同的异常:

    public static float Noise(int x)
    {
        x = (x << 13) ^ x;
        checked{
            return (1f - ((x * (x * x * 15731) + 1376312589) & 0x7FFFFFFF) / 1073741824.0f);
        }
    }
    

    我该怎么做才能让它在 VB.net 中也能正常工作?

    我怀疑它是否适用于 C#。由于它无声地溢出,您可能会得到不正确的结果。

    但是,您可以通过将x 转换为双精度来防止溢出:

    Private Function Noise(ByVal x As Integer) As Double
        x = (x << 13) Xor x
    
        Dim y As Double = x
    
        Return (1.0R - ((y * (y * y * 15731.0R) + 1376312589.0R) And &H7FFFFFFF) / 1073741824.0R)
    End Function
    

    您还可以打开 VB 项目的“删除整数溢出检查”属性,但这是项目范围的设置。 VB 目前没有办法像 C# 那样关闭对特定代码行的溢出检查。

    无论您做什么,我都会对其进行彻底测试,因为您正在计算一个浮点值,对其进行位掩码 (And &amp;H7FFFFFFF),然后除以另一个浮点值。混合整数和浮点数学可能非常棘手。

    另请注意,您的两个代码段是不等价的。您的 C# 函数返回 float,而 VB 返回 Double。而且您在 VB 中使用浮点文字,但在 C# 中使用整数文字。这可能看起来差别不大,但它可以意外地改变数学。

    【讨论】:

    • 我已经尝试将 x 转换为双精度甚至小数,然后 OverflowException 出现 x=11。
    • 我建议找一个不需要这么大数字的方法,或者关闭 VB 项目的溢出检查。
    【解决方案2】:

    就像 D Stanley 指出的那样,VB.net 中 OverFlowException 的原因是 VB.net 会自动对整数运算进行溢出检查,而 C# 则不会。

    如果其他人有兴趣让它在 VB.net 中工作,您可以执行以下操作:

    将此结构添加到您的项目中

    <StructLayout(LayoutKind.Explicit)>
    Public Structure LongToIntegerNoOverflow
        <FieldOffset(0)>
        Public LongValue As Long
        <FieldOffset(0)>
        Public IntValue As Integer
    End Structure
    

    并将噪声函数更改为

    Private Function Noise(ByVal x As Integer) As Single
        Dim x1 As Long
        Dim x2 As LongToIntegerNoOverflow
        Dim x3 As LongToIntegerNoOverflow
        Dim x4 As Long
    
        x1 = (x << 13) Xor x
    
        x2.LongValue = x1 * x1 * 15731 + 789221
        x3.LongValue = x1 * x2.IntValue + 1376312589
    
        x4 = x3.IntValue And &H7FFFFFFF
    
        Return (1.0R - x4 / 1073741824.0R)
    End Function
    

    在这些更改之后,我在 VB.net 和 C# 中得到了相同的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-28
      • 2011-12-26
      • 1970-01-01
      • 2015-10-14
      • 2013-02-21
      • 1970-01-01
      相关资源
      最近更新 更多