C:设置变量范围内所有位的最有效方法

时间:2014-03-26 13:41:21

标签: c bit-manipulation

我们以int为例:

int SetBitWithinRange(const unsigned from, const unsigned to)
{
    //To be implemented 
} 

SetBitWithinRange应该返回int,其中所有且仅从位from到位to的位被设置,当来自{{1}时比smaller而且两者都在to0的范围内。

例如为: 32会导致int i = SetBitWithinRange(2,4)的值为0b00 ... 01100

7 个答案:

答案 0 :(得分:5)

以下是一些方法。首先,“set n位的一些变体,然后由from”移位。我会用C#回答,我比它更熟悉它。应该很容易转换。

uint nbits = 0xFFFFFFFFu >> -(to - from);
return nbits << from;

下行:无法处理空范围,即to <= from

的情况
uint nbits = ~(0xFFFFFFFFu << (to - from));
return nbits << from;

上行:可以处理to = from的情况,在这种情况下,它不会设置位 下行:无法处理全部范围,即设置所有位。

显然这些是如何工作的。

或者,您可以使用“减去两个2的幂”技巧,

(1u << to) - (1u << from)

下行:to不能为32,所以你永远不能设置最高位。

像这样工作:

01000000
  ^^^^^^ "to" zeroes
     100
      ^^ "from zeroes"
-------- -
00111100

在“from”部分的1的右侧,它只是从零中减去零。然后在“from”部分的1处,您将从1减去(如果to == from)并得到0作为结果,或者您将从0减去1并一直借用到to部分中的1,将被重置。

在撰写本文时提出的所有真正的按位方法都有其中一个缺点,这就提出了一个问题:它可以毫无缺点地完成吗?

不幸的是,答案令人失望。它可以在没有缺点的情况下完成,但仅限于

  1. 作弊(即使用非按位元素)或
  2. 比不太好的操作或
  3. 非标准操作
  4. 举一个例子,您可以选择以前的任何方法,并添加一个特殊情况(使用if或三元运算符)来解决它们的缺点。

    举例2 :(未经测试)

    uint uppermask = (((uint)to >> 5) ^ 1) << to;
    return uppermask - (1u << from);
    

    uppermask取1并将其向左移动to(照例),或者取0并向左移动(量数无关紧要,因为它为0正在转移),如果to == 32。但它有点奇怪并且使用更多操作。

    举一个3的例子,当你按操作数大小移动时给出零的移位可以很容易地解决这个问题。不幸的是,这种转变并不常见。

答案 1 :(得分:3)

我会选择类似的东西:

int answer = 0;
unsigned i = from;
for (; i <= to; ++i)
  answer |= (1 << i);

return answer;

易于实施&amp;可读的。

我认为最快的方法是预先计算所有可能的值(从(0,0)到(32,32),如果你知道你只将它用于32位整数) 。事实上,其中大约有1000个。

然后你最终会得到O(1)解决方案:

answer = precalcTable[from][to];

答案 2 :(得分:3)

好吧,我正在接受@JohnZwinck向我投掷的挑战。

怎么样: return (to<32 ? (1<<to) : 0) - (1<<from);

当然,这并未完全检查fromto的有效性。

根据@JosephQuinsey的评论编辑。

答案 3 :(得分:2)

有效地实现这一目标的常见方法是:

uint32_t set_bits_32 (uint32_t data, uint8_t offset, uint8_t n)
{
  uint32_t mask = 0xFFFFFFFF >> (32-n);

  return data | (mask << offset);
}

答案 4 :(得分:1)

也许:(( 1 << to ) - (1 << from)) | (1 << to)

这也将根据请求设置to和from

答案 5 :(得分:1)

这是我的答案。 (更新

unsigned int SetBits(int from, int to)
{    
    return (UINT_MAX >> (CHAR_BIT*sizeof(int)-to)) & (UINT_MAX << (from-1));
}

SetBits(9,16); ==> 0b 1111 1111 0000 0000

SetBits(1,1); ==> 0b 0000 0001  // Just Bit #1
SetBits(5,5); ==> 0b 0001 0000  // Just Bit #5
SetBits(1,4); ==> 0b 0000 1111  // Bits #1, #2, #3, and #4 (low 4 bits) 
SetBits(1,32); ==> 0b 1111 1111 1111 1111  // All Bits

但是,SetBits(0,0);无法关闭所有位。

我的假设:

  • 比特从1开始,从右边开始。
  • 字节是8位。
  • Ints可以是任何大小(16,32或64位)。使用了sizeof(int)。
  • 未对fromto进行检查;调用者必须传递正确的值。

答案 6 :(得分:0)

也可以这种方式完成,可以使用移位操作实现pow。

{
    unsigned int i =0;
    i = pow(2, (to-from))-1;
    i = i <<from;
    return i;
}