在不浪费 space 的情况下,在字节数组上对小数值进行位掩码?
Bitmasking small numeric values over a byte array without wasting space in c#?
我正在尝试扩展 一点,将其扩展为涵盖打包到 byte[] 数据结构中的 5 位值。
我要实现的具体 objective 是使用 get/set 函数将总共 128 个 5 位 (0-31) 数值存储在一个 80 字节的数组中访问和操作数组中的值。
有人有这方面的经验吗?
编辑:
感谢 Guffa 在下面接受的答案中,这是他的 class 用于静态调用的内联版本:
byte Get_5_In_BA(ref byte[] storage, int index)
{
int bigIndex = (index * 5) / 8;
int smallIndex = (index * 5) % 8;
if (smallIndex > 3)
{
return ((byte) (((storage[bigIndex] + (storage[bigIndex + 1] * 0x0100)) >> smallIndex) & 0x1F));
}
return ((byte) ((storage[bigIndex] >> smallIndex) & 0x1F));
}
void Set_5_In_BA(ref byte[] storage, int index, byte value)
{
if (value > 31) { value = 31; }
int bigIndex = (index * 5) / 8;
int smallIndex = (index * 5) % 8;
int mask = 0x1F << smallIndex;
storage[bigIndex] = (byte) ((storage[bigIndex] & ~mask) | (value << smallIndex));
if (smallIndex > 3)
{
storage[bigIndex + 1] = (byte) ((storage[bigIndex + 1] & ~(mask >> 8)) | (value >> (8 - smallIndex)));
}
}
应该这样做:
public class FiveBit {
private byte[] _data;
public FiveBit(int len) {
_data = new byte[(len * 5 + 7) / 8];
}
public int this[int index] {
get {
int i = index * 5 / 8;
int ofs = index * 5 % 8;
if (ofs > 3) {
return ((_data[i] + _data[i + 1] * 256) >> ofs) & 31;
} else {
return (_data[i] >> ofs) & 31;
}
}
set {
int i = index * 5 / 8;
int ofs = index * 5 % 8;
int mask = 31 << ofs;
_data[i] = (byte)((_data[i] & ~mask) | (value << ofs));
if (ofs > 3) {
_data[i + 1] = (byte)((_data[i + 1] & ~(mask >> 8)) | (value >> (8 - ofs)));
}
}
}
}
注意:这没有经过全面测试,但我已经测试过我可以在其中放入 128 个随机 5 位值,并再次得到相同的值。您还应该在参数上添加一些范围检查以使代码更健壮,而且我没有过多考虑 class 名称,因此您肯定可以编写更好地描述它的内容。
我正在尝试扩展
我要实现的具体 objective 是使用 get/set 函数将总共 128 个 5 位 (0-31) 数值存储在一个 80 字节的数组中访问和操作数组中的值。
有人有这方面的经验吗?
编辑:
感谢 Guffa 在下面接受的答案中,这是他的 class 用于静态调用的内联版本:
byte Get_5_In_BA(ref byte[] storage, int index)
{
int bigIndex = (index * 5) / 8;
int smallIndex = (index * 5) % 8;
if (smallIndex > 3)
{
return ((byte) (((storage[bigIndex] + (storage[bigIndex + 1] * 0x0100)) >> smallIndex) & 0x1F));
}
return ((byte) ((storage[bigIndex] >> smallIndex) & 0x1F));
}
void Set_5_In_BA(ref byte[] storage, int index, byte value)
{
if (value > 31) { value = 31; }
int bigIndex = (index * 5) / 8;
int smallIndex = (index * 5) % 8;
int mask = 0x1F << smallIndex;
storage[bigIndex] = (byte) ((storage[bigIndex] & ~mask) | (value << smallIndex));
if (smallIndex > 3)
{
storage[bigIndex + 1] = (byte) ((storage[bigIndex + 1] & ~(mask >> 8)) | (value >> (8 - smallIndex)));
}
}
应该这样做:
public class FiveBit {
private byte[] _data;
public FiveBit(int len) {
_data = new byte[(len * 5 + 7) / 8];
}
public int this[int index] {
get {
int i = index * 5 / 8;
int ofs = index * 5 % 8;
if (ofs > 3) {
return ((_data[i] + _data[i + 1] * 256) >> ofs) & 31;
} else {
return (_data[i] >> ofs) & 31;
}
}
set {
int i = index * 5 / 8;
int ofs = index * 5 % 8;
int mask = 31 << ofs;
_data[i] = (byte)((_data[i] & ~mask) | (value << ofs));
if (ofs > 3) {
_data[i + 1] = (byte)((_data[i + 1] & ~(mask >> 8)) | (value >> (8 - ofs)));
}
}
}
}
注意:这没有经过全面测试,但我已经测试过我可以在其中放入 128 个随机 5 位值,并再次得到相同的值。您还应该在参数上添加一些范围检查以使代码更健壮,而且我没有过多考虑 class 名称,因此您肯定可以编写更好地描述它的内容。