Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Packing multiple signed integers into a single 64-bit value [closed]

Tags:

c#

64-bit

I need to pack and unpack several values to/from a single 64-bit value. I have 3 signed integers (x,y,z). I would like to pack them into a single 64-bit value (signed or unsigned doesn't matter to me) using 24, 16, and 24 bits for the values respectively. Here are my requirements:

1) I can ensure ahead of times that the values being stored do not exceed the limits of the number of bits I am using to store them into the 64-bit value, so no additional checks need to be made.

2) The initial values are signed, so I'm thinking some kind of bit magic may need to be done in order to ensure that nothing is lost.

3) This conversion is going to take place a LOT, so it needs to be fast. I know in C++ this can pretty easily be done by storing the values in a struct that specifies the integer length, and then establishing a pointer that just points to the first value that can be used for the 64-bit value. With this method, there really isn't any math that needs done, everything is just memory read or right. As far as I can tell, this can't be done quite so simply in C#, but C# is what I have to work with for this project.

4) I don't really care if the 64-bit value is signed or unsigned, so long as I can go both ways with the operation and recover the initial values, and whatever type is used can be used for a Dictionary key.

like image 256
Will Russell Avatar asked Nov 28 '22 13:11

Will Russell


1 Answers

Masks and shifts are probably your best option. You can create explicit layout structs in C#, but there's no 24-bit primitive, so you'd be tripping over yourself and have to mask anyway. As soon as you're shifting, it is usually best to work unsigned (especially when right-shifting), so:

ulong val = ((((ulong)x) & 0xFFFFFF) << 40) // 24 bits of x, left-shifted by 40
          | ((((ulong)y) & 0xFFFF) << 24) // 16 bits of y, left-shifted by 24
          | (((ulong)z) & 0xFFFFFF); // 24 bits of z, no left-shift

and to reverse that (assuming that we want uint values):

uint a = (uint)((val >> 40) & 0xFFFFFF),
     b = (uint)((val >> 24) & 0xFFFF),
     c = (uint)(val & 0xFFFFFF);
like image 139
Marc Gravell Avatar answered Dec 18 '22 06:12

Marc Gravell