所以,bitfields。具体来说,是大位域。我理解如何操作位域中的单个值,但是如何在大型集合上执行此操作,例如:
uint[] bitfield = new uint[4] { 0x0080000, 0x00FA3020, 0x00C8000, 0x0FF00D0 };
我遇到的具体问题是在整个阵列中进行左右移位。例如,如果我在上面的数组上做了>> 4
,我最终得到:
uint[4] { 0x0008000, 0x000FA302, 0x000C800, 0x00FF00D };
现在,这里的(过于简单的)算法可能看起来像(这是我在运行中编写代码):
int shift = 4;
for (int i = 0; i <= shift; i++) {
for (int j = bitfield.GetUpperBound(0); j > 0; j--) {
bitfield[j] = bitfield[j] >> 1;
bitfield[j] = bitfield[j] + ((bitfield[j-1] & 1) << (sizeof(uint)*8));
}
bitfield[0] = bitfield[0] >> 1;
}
是否内置了可以轻松处理此类数据的内容?
答案 0 :(得分:2)
是什么让你认为BitArray在内部使用bool?它使用布尔值来表示API方面的位,但我认为它使用了int []。
答案 1 :(得分:1)
我不确定这是否是最佳方式,但这可行(将班次限制在0-31范围内。
public static void ShiftLeft(uint[] bitfield, int shift) {
if(shift < 0 || shift > 31) {
// handle error here
return;
}
int len = bitfield.Length;
int i = len - 1;
uint prev = 0;
while(i >= 0) {
uint tmp = bitfield[i];
bitfield[i] = bitfield[i] << shift;
if(i < len - 1) {
bitfield[i] |= (uint)(prev & (1 >> shift) - 1 ) >> (32 - shift);
}
prev = tmp;
i--;
}
}
public static void ShiftRight(uint[] bitfield, int shift) {
if(shift < 0 || shift > 31) {
// handle error here
return;
}
int len = bitfield.Length;
int i = 0;
uint prev = 0;
while(i < len) {
uint tmp = bitfield[i];
bitfield[i] = bitfield[i] >> shift;
if(i > 0) {
bitfield[i] |= (uint)(prev & (1 << shift) - 1 ) << (32 - shift);
}
prev = tmp;
i++;
}
}
PD:通过此更改,您应该能够处理大于31位的移位。可以重构以使它看起来不那么难看,但在我的测试中,它可以工作,并且在性能方面似乎并不太糟糕(除非,实际上有一些内置处理大型位集的情况,可能就是这种情况)。
public static void ShiftLeft(uint[] bitfield, int shift) {
if(shift < 0) {
// error
return;
}
int intsShift = shift >> 5;
if(intsShift > 0) {
if(intsShift > bitfield.Length) {
// error
return;
}
for(int j=0;j < bitfield.Length;j++) {
if(j > intsShift + 1) {
bitfield[j] = 0;
} else {
bitfield[j] = bitfield[j+intsShift];
}
}
BitSetUtils.ShiftLeft(bitfield,shift - intsShift * 32);
return;
}
int len = bitfield.Length;
int i = len - 1;
uint prev = 0;
while(i >= 0) {
uint tmp = bitfield[i];
bitfield[i] = bitfield[i] << shift;
if(i < len - 1) {
bitfield[i] |= (uint)(prev & (1 >> shift) - 1 ) >> (32 - shift);
}
prev = tmp;
i--;
}
}
public static void ShiftRight(uint[] bitfield, int shift) {
if(shift < 0) {
// error
return;
}
int intsShift = shift >> 5;
if(intsShift > 0) {
if(intsShift > bitfield.Length) {
// error
return;
}
for(int j=bitfield.Length-1;j >= 0;j--) {
if(j >= intsShift) {
bitfield[j] = bitfield[j-intsShift];
} else {
bitfield[j] = 0;
}
}
BitSetUtils.ShiftRight(bitfield,shift - intsShift * 32);
return;
}
int len = bitfield.Length;
int i = 0;
uint prev = 0;
while(i < len) {
uint tmp = bitfield[i];
bitfield[i] = bitfield[i] >> shift;
if(i > 0) {
bitfield[i] |= (uint)(prev & (1 << shift) - 1 ) << (32 - shift);
}
prev = tmp;
i++;
}
}
答案 2 :(得分:0)
使用扩展方法,您可以这样做:
public static class BitArrayExtensions
{
public static void DownShift(this BitArray bitArray, int places)
{
for (var i = 0; i < bitArray.Length; i++)
{
bitArray[i] = i + places < bitArray.Length && bitArray[i + places];
}
}
public static void UpShift(this BitArray bitArray, int places)
{
for (var i = bitArray.Length - 1; i >= 0; i--)
{
bitArray[i] = i - places >= 0 && bitArray[i - places];
}
}
}
不幸的是,我无法想出一种方法来重置移位运算符。 (主要是因为BitArray
被密封了。)
如果您打算操纵int
或uint
,您可以创建扩展方法,以便将位插入/提取BitArray
中的位。 (BitArray
有一个构造函数,它接受int
个数组,但这只会带你那么远。)
答案 3 :(得分:0)
这不包括具体的移位,但对于处理大型集合可能很有用。它在C中,但我认为它可以很容易地适应C#