9

我有一个项目,我想默认检查算术,除了一个性能敏感点。不幸的是,VB.Net 没有“未检查”块。

理想情况下,该框架将具有某种带有明确未经检查的算术的整数类型,但我没有找到类似的东西。我确实发现表达式树具有用于未经检查的操作的二进制表达式,但委托开销抵消了未经检查的优势(然后是一些)。

目前,我在进行算术运算之前将输入转换为 UInt64/Int64,然后再转换回来(使用按位 And 以确保在范围内)。它比未经检查的算术(根据分析)慢约 50%。

将算术敏感部分移动到具有未经检查的算术的项目中可能会起作用,但是将其全部单独提供给它似乎有点过头了。

4

3 回答 3

6

我知道这很旧,但我最近需要转换一些未经检查的 C# 代码,我想我会分享我是如何做到的。它是纯 VB 代码,可以根据需要调整范围(而不是项目范围的选项)。

诀窍是创建一个包含一个 Long 字段和两个 Integer 字段的结构。然后使用 StructLayout 和 FieldOffset 属性来创建 long 和两个整数的并集。这些字段可以(应该)是私有的。使用扩展 CType 运算符从 Long 转换为结构,从结构转换为 Integer(使用低整数值)。为 +、-、* 等添加运算符重载……然后!VB中未经检查的算术!

有点......它仍然会溢出,正如 Strilanc 指出的那样,如果 long 值超出 long 的范围。但它适用于许多使用 unchecked 的情况。

这是一个例子:

<StructLayout(LayoutKind.Explicit)>
Public Structure UncheckedInteger

    <FieldOffset(0)>
    Private longValue As Long
    <FieldOffset(0)>
    Private intValueLo As Integer
    <FieldOffset(4)>
    Private intValueHi As Integer

    Private Sub New(newLongValue As Long)
        longValue = newLongValue
    End Sub

    Public Overloads Shared Widening Operator CType(value As Long) As UncheckedInteger
        Return New UncheckedInteger(value)
    End Operator

    Public Overloads Shared Widening Operator CType(value As UncheckedInteger) As Long
        Return value.longValue
    End Operator

    Public Overloads Shared Widening Operator CType(value As UncheckedInteger) As Integer
        Return value.intValueLo
    End Operator

    Public Overloads Shared Operator *(x As UncheckedInteger, y As Integer) As UncheckedInteger
        Return New UncheckedInteger(x.longValue * y)
    End Operator

    Public Overloads Shared Operator Xor(x As UncheckedInteger, y As Integer) As UncheckedInteger
        Return New UncheckedInteger(x.longValue Xor y)
    End Operator

    ' Any other operator overload you need...
End Structure

在代码中使用如下结构:

Dim x As UncheckedInteger = 2147483647
Dim result As Integer = x * 2  ' This would throw OverflowException using just Integers

Console.WriteLine(result.ToString())  ' -2

在将结果分配给 UncheckedInteger 之前,请注意您的计算不会溢出。您可以使用相同的技术创建 UncheckedShort 和 UncheckedByte 结构。

于 2013-03-26T23:47:49.890 回答
2

就个人而言,我认为将它留在自己的程序集中,特别是因为它是一个如此小的程序集,是一个不错的选择。这使得维护更容易,因为随时可以轻松地重新生成此组件。只需将一个单独的程序集标记为未选中,然后将您的性能敏感代码放在那里。

于 2010-03-08T17:22:30.747 回答
0

我最近在 VB.NET 中为未经检查的整数操作创建了一个 nuget 包,请参阅 nuget 包VBMath.Unchecked或 Github 存储库System.Runtime.Extensions.Unchecked

Using System.Numerics

' this will not throw
Dim value = UncheckedInteger.Add(Integer.MaxValue, 1)
于 2020-04-25T09:55:56.937 回答