Question

I have a project where I want to have checked arithmetic by default, except for one performance sensitive spot. Unfortunately, VB.Net doesn't have an 'unchecked' block.

Ideally the framework would have some sort of integer type with explicitly unchecked arithmetic, but I didn't find anything like that. I did find that expression trees have binary expressions for unchecked operations, but the delegate overhead cancels out the unchecked advantage (and then some).

Currently I'm converting the inputs to UInt64/Int64 before doing the arithmetic, then converting back (with a bitwise And to ensure in-range). It's about 50% slower than unchecked arithmetic (according to profiling).

Moving the arithmetic-sensitive part to a project with unchecked arithmetic might work, but it seems like overkill to give it an assembly all to itself.

Was it helpful?

Solution

Personally, I think leaving this in its own assembly, especially since it'll be such a small assembly, is a good option. This makes maintenance easier, since it's easy to regenerate this assembly at any time. Just make a separate assembly flagged unchecked, and put your performance-sensitive code there.

OTHER TIPS

I know this is old, but I recently needed to convert some C# code that used unchecked and I thought I'd share how I did it. It's pure VB code and can be scoped however you need (rather than a project-wide option).

The trick is to create a structure that contains a Long field and two Integer fields. Then use StructLayout and FieldOffset attributes to create a union of the long and the two integers. The fields can (should) be private. Use widening CType operators to convert from a Long to the structure and from the structure to an Integer (using the low integer value). Add operator overloads for +, -, *, etc... and presto! unchecked arithmetic in VB!

Sort of... it will still overflow, as Strilanc pointed out, if the long value goes outside the range for longs. But it works pretty well for a lot of situations where unchecked is used.

Here's an example:

<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

Use the structure in code like this:

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

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

Careful that your calculations don't overflow before assigning the result to an UncheckedInteger. You could create UncheckedShort and UncheckedByte structures using the same technique.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top