Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast casting in C# using BitConverter, can it be any faster?

In our application, we have a very large byte-array and we have to convert these bytes into different types. Currently, we use BitConverter.ToXXXX() for this purpose. Our heavy hitters are, ToInt16 and ToUInt64.

For UInt64, our problem is that the data stream has actually 6-bytes of data to represent a large integer. Since there is no native function to convert 6-bytes of data to UInt64, we do:

UInt64 value = BitConverter.ToUInt64() & 0x0000ffffffffffff;

Our use of ToInt16 is simpler, do don't have to do any bit manipulation.

We do so many of these 2 operations that I wanted to ask the SO community whether there's a faster way to do these conversions. Right now, approximately 20% of our entire CPU cycles is consumed by these two functions.

like image 797
SomethingBetter Avatar asked Feb 07 '11 16:02

SomethingBetter


People also ask

Can you cast variables in C?

In C, When you convert the data type of a variable to another data type then this technique is known as typecasting. Let's say that you want to store a value of int data type into a variable of float data type. Then you can easily do this with the help of typecasting.

What is casting operator in C?

Cast operator () In C, the result of the cast operation is not an lvalue. In C++, the cast result belongs to one of the following value categories: If type is an lvalue reference type. or an rvalue reference to a function type.

What is automatic type conversion in C?

Also known as 'automatic type conversion'. Done by the compiler on its own, without any external trigger from the user. Generally takes place when in an expression more than one data type is present. In such condition type conversion (type promotion) takes place to avoid loss of data.


2 Answers

Have you thought about using memory pointers directly. I can't vouch for its performance but it is a common trick in C++\C...

        byte[] arr = { 1, 2, 3, 4, 5, 6, 7, 8 ,9,10,11,12,13,14,15,16};

        fixed (byte* a2rr = &arr[0])
        {

            UInt64* uint64ptr = (UInt64*) a2rr;
            Console.WriteLine("The value is {0:X2}", (*uint64ptr & 0x0000FFFFFFFFFFFF));
            uint64ptr = (UInt64*) ((byte*) uint64ptr+6);
            Console.WriteLine("The value is {0:X2}", (*uint64ptr & 0x0000FFFFFFFFFFFF));
        }

You'll need to make your assembly "unsafe" in the build settings as well as mark the method in which you'd be doing this unsafe aswell. You are also tied to little endian with this approach.

like image 168
Jimmy Avatar answered Oct 22 '22 05:10

Jimmy


You can use the System.Buffer class to copy a whole array over to another array of a different type as a fast, 'block copy' operation:

The BlockCopy method accesses the bytes in the src parameter array using offsets into memory, not programming constructs such as indexes or upper and lower array bounds.

The array types must be of 'primitive' types, they must align, and the copy operation is endian-sensitive. In your case of 6-bytes integers, it can't align with any of .NET's 'primitive' types, unless you can obtain the source array with two bytes of padding for each six, which will then align to Int64. But this method will work for arrays of Int16, which may speed up some of your operations.

like image 43
Allon Guralnek Avatar answered Oct 22 '22 06:10

Allon Guralnek