I'm trying to store four independent 5-bit values (0-31) inside a 32-bit int via bit mask but am having trouble getting the values correct to set and get the individual values from the masked int used for storage.
Can anyone help me with this?
Edit:
Sorry for the external link - here's some JavaScript demonstrating what I'm trying to achieve (but in bitmasks instead of decimal algebra):
var s = 0;
var v = [31, 6, 23, 31];
//save values
s = v[0] + (v[1] * 32) + (v[2] * 1024) + (v[3] * 32768);
console.log(s);
//retrieve values
v[3] = parseInt(s / 32768);
v[2] = parseInt((s - (v[3] * 32768)) / 1024);
v[1] = parseInt((s - ((v[3] * 32768) + (v[2] * 1024))) / 32);
v[0] = parseInt(s - ((v[3] * 32768)+ (v[2] * 1024) + (v[1] * 32)));
console.log(v);
//modify values [1] and [2]
s = s - (v[1] * 32) + (9 * 32);
s = s - (v[2] * 1024) + (17 * 1024);
console.log(s);
//retrieve values
v[3] = parseInt(s / 32768);
v[2] = parseInt((s - (v[3] * 32768)) / 1024);
v[1] = parseInt((s - ((v[3] * 32768) + (v[2] * 1024))) / 32);
v[0] = parseInt(s - ((v[3] * 32768)+ (v[2] * 1024) + (v[1] * 32)));
console.log(v);
Output:
1039583
[31, 6, 23, 31]
1033535
[31, 9, 17, 31]
Edit:
Thanks to Peter Duniho I was able to make these with the masks build in to save some operations for 6 5-bit values inside a 32-bit integer:
uint Get_5_In_32(uint storage, int index)
{
switch (index)
{
case 0:
return (storage & 0x0000001F);
case 1:
return (storage & 0x000003E0) >> 5;
case 2:
return (storage & 0x00007C00) >> 10;
case 3:
return (storage & 0x000F8000) >> 15;
case 4:
return (storage & 0x01F00000) >> 20;
case 5:
return (storage & 0x3E000000) >> 25;
default:
return (0);
}
}
uint Set_5_In_32(uint storage, uint value, int index)
{
if (value > 31) { value = 31; }
switch (index)
{
case 0:
return (storage & 0xFFFFFFE0) | value;
case 1:
return (storage & 0xFFFFFC1F) | (value << 5);
case 2:
return (storage & 0xFFFF83FF) | (value << 10);
case 3:
return (storage & 0xFFF07FFF) | (value << 15);
case 4:
return (storage & 0xFE0FFFFF) | (value << 20);
case 5:
return (storage & 0xC1FFFFFF) | (value << 25);
default:
return (0);
}
}
And a byref version of the Set function for even less allocation:
void Set_5_In_32(ref uint storage, uint value, int index)
{
if (value > 31) { value = 31; }
switch (index)
{
case 0:
storage &= 0xFFFFFFE0;
storage |= value;
break;
case 1:
storage &= 0xFFFFFC1F;
storage |= (value << 5);
break;
case 2:
storage &= 0xFFFF83FF;
storage |= (value << 10);
break;
case 3:
storage &= 0xFFF07FFF;
storage |= (value << 15);
break;
case 4:
storage &= 0xFE0FFFFF;
storage |= (value << 20);
break;
case 5:
storage &= 0xC1FFFFFF;
storage |= (value << 25);
break;
}
}
Without a more specific question, and in particular you showing the code you have so far and explaining what you're having trouble specifically in terms of getting it to work, it's hard to know exactly what the best answer would be.
That said, here are a couple of example methods that might get you pointed in the right direction:
The
Set()
method above takes the current value instorage
, clears all of the bits in the range of bits where you want to store your five-bit value, and then uses the|
operator to store that five-bit value, shifting the bits of that value to the right place first.The
Get()
method performs the reverse operation. It masks off (clears) all of the bits not in the range of bits where the value was stored, and then shifting the stored bits down to the least-significant five bits of anint
before returning that result.Notes:
value
passed to theSet()
method does in fact fit in five bits (i.e. is less than0x20
).EDIT:
Here is a simple console program that demonstrates the use of the above, with your example data: