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

我们以int为例:

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

SetBitWithinRange应该返回一个int ,其中当from smaller to且两者都在032的范围内时,所有且仅仅从bit到bit的位开始被设置。

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

这是一些方法。 首先,“设置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) 

缺点:不能是32,所以你永远不能设置最高位。

像这样工作:

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

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

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

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

  1. 作弊(即使用非按位元素),或
  2. 更多的操作比不好,或
  3. 非标准操作

举一个例子,您可以选择任何以前的方法并添加一个特殊情况(使用if或三元运算符)来解决它们的缺点。

举两个例子:(未经测试)

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

上面的uppermask要么取一个1并将其向左移动(如通常那样),要么取一个0并向左移动(一个无关紧要的量,因为它是0被移位),如果to == 32 。 但它有点奇怪并且使用更多操作。

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

我会选择这样的东西:

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

易于实现和可读。

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

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

 answer = precalcTable[from][to]; 

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

怎么样: return (to<32 ? (1<

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

根据@JosephQuinsey的评论编辑。

有效地执行此操作的常见方法是:

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

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

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

这是我的答案。 ( 更新

 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)。
  • 没有检查是否from ; 调用者必须传递适当的值。

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

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