在圆形位字段中设置位范围

时间:2012-04-05 22:23:13

标签: c# bit-manipulation

我有一个由64位组成的位字段:

long bitfield = 0;

我可以按如下方式设置给定索引的位:

void Set(long index)
{
   bitfield |= 1L << (int)(index % 64);
}

即。如果索引是0,64,128,...则设置位0,如果索引是1,65,129,...则设置位1,依此类推。

问题:给定索引和计数(或者上下索引),如何在不使用循环的情况下设置此范围内所有索引的位?

3 个答案:

答案 0 :(得分:3)

long SetRangeMask(int lower, int upper)     // 3..7
{
   if (! (lower <= upper)) throw new ArgumentException("...");

   int size = upper - lower + 1;            // 7 - 3 + 1 = 5
   if (size >= 64) return -1;
   long mask = (1 << size) - 1;             // #00100000 - 1  = #000011111
   return mask << lower | mask >> -lower;   // #00011111 << 3 = #011111000
}

答案 1 :(得分:1)

您可以使用查找表来组合位掩码

一个真正的简单方法,没有考虑特殊情况或优化,如这些问题,如下所示:

 static readonly private long[] maskLUT = new long[64,64] { /* generated */ };

 void SetRange(long lobit, long hibit)
 {
     lobit %= 64;
     hibit %= 64;

     bitfield |= lobit<hibit? maskLUT[lobit,hibit] : maskLUT[hibit,lobit];
 }

思考:

  • 您可能会考虑给定[lobit...hibit]的优化,如果hibit-lobit&gt; = 64,您可以一次设置所有位。

  • 考虑到两个边界都可以环绕(或者首先包裹两个边界,或者环绕lobit这个事实,有一些想法被放在区域的连通性中,并使用delta从包装边界中找到hibit,就像之前提到的优化一样?)

答案 2 :(得分:0)

您可以使用2 x -1来创建一个x位长的掩码,然后将其移位并将其移入,如下所示:

void Set( int index, int count ) {
  bitfield |= (long)(Math.Pow( 2, count ) - 1) << ((index-count) % 64);
}

更新:我认为Math.Pow可以优化左移两个的力量,但可能不会。如果是这种情况,您可以通过将Math.Pow的调用替换为相应的左移来获得更多性能:

public void Set( int index, int count ) {
  bitfield |= ((2 << count - 1) - 1) << ((index-count) % 64);
}