Last active
July 8, 2023 04:16
-
-
Save Alan-FGR/04938e93e2bffdf5802ceb218a37c195 to your computer and use it in GitHub Desktop.
Packing Bits in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
class PackingBits | |
{ | |
static void Main(string[] args) | |
{ | |
// say you have this data: | |
byte byteA = 7; | |
byte byteB = 5; | |
ushort someNumber = 1500; | |
// you pack that into an uint like this: | |
byte[] packingFormat = {8, 8, 16}; | |
ushort[] dataToPack = { byteA, byteB, someNumber }; | |
uint packedData = PackBitFields(dataToPack, packingFormat); | |
// print the value | |
Console.Write("packed: "); | |
foreach (ushort v in dataToPack) { Console.Write(v + ", "); } | |
Console.WriteLine("into: "+packedData); | |
//now you unpack the data back | |
ushort[] unpackedData = GetBitFields(packedData, packingFormat); | |
// print for confirmation (you may want to cast back) | |
Console.Write("unpacked: "); | |
foreach (ushort v in unpackedData) {Console.Write(v + ", ");} | |
Console.WriteLine(); | |
//##################################### | |
//another example | |
byte[] format2 = new byte[] {4,4,4,4,4,4,4,4}; | |
uint packedData2 = PackBitFields(new ushort[]{1,2,3,4,11,12,13,14}, format2); | |
ushort[] unpackedData2 = GetBitFields(packedData2, format2); | |
// print for confirmation - WHOAH! 8 numbers in a single UINT! (32-bit) :) | |
Console.Write("unpacked: "); | |
foreach (ushort v in unpackedData2) { Console.Write(v + ", "); } | |
Console.WriteLine(); | |
//##################################### | |
// here's a more useful example: | |
uint packedColor = PackBitFields(new ushort[] { 31, 0, 0, 0, 63, 0 }, RGBRGB565565); | |
var unpackedColor = GetBitFields(packedColor, RGBRGB565565); | |
// RED AND GREEN in a uint | |
Console.Write("unpacked: "); | |
foreach (ushort v in unpackedColor) { Console.Write(v + ", "); } | |
Console.WriteLine(); | |
} | |
const int MaxBits = 32; // you may want to pass this and use generics to allow more or less bits | |
static readonly byte[] RGBRGB565565 = { 5,6,5,5,6,5 }; // make some common formats like this | |
public static uint PackBitFields(ushort[] values, byte[] bitFields) | |
{ | |
uint retVal = values[0]; //we set the first value right away | |
for (int f = 1; f < values.Length; f++) | |
{ | |
retVal <<= bitFields[f]; //we shift the previous value | |
retVal += values[f]; //and add our current value //on some processors | (pipe) will be faster here | |
} | |
return retVal; | |
} | |
public static ushort[] GetBitFields(uint packedBits, byte[] bitFields) | |
{ | |
int fields = bitFields.Length-1; // number of fields to unpack | |
ushort[] retArr = new ushort[fields+1]; // init return array | |
int curPos = 0; // current field bit position (start) | |
int lastEnd; // position where last field ended | |
for (int f = fields; f >= 0; f--) // loop from last | |
{ | |
lastEnd = curPos; // we store where the last value ended | |
curPos += bitFields[f]; // we get where the current value starts | |
int leftShift = MaxBits - curPos; // we figure how much left shift we gotta apply for the other numbers to overflow into oblivion | |
retArr[f] = (ushort)((packedBits << leftShift) >> leftShift + lastEnd); // we do magic | |
} | |
return retArr; | |
} | |
} |
For some reason, on line 61 addition is faster on a Haswell Pentium G, while 'logic OR' (pipe) is faster on a Haswell i7... the mysteries of modern computing... in any case the difference between + and | is below 1ns per million operations, relative to the total cost of a million of PackBitFields which is about 10ms that's negligible.
Compared to the BitConverter though, a throughput of 100 million ops/second isn't very impressive, although we are using the bits in a much more efficient way and retrieving more variables. I'm going to do a fair comparison someday...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Read usage and proper applications here: http://alangamedev.com/mind-your-bits/
If you came here through Google, this is most likely premature optimization, i.e.: the root of all evil.