我们以int
为例举个例子:
int SetBitWithinRange(const unsigned from, const unsigned to)
{
//To be implemented
}
SetBitWithinRange
应该返回 int
其中所有且只有从位 from
开始的位到位to
被设置,当 from 是 smaller
比to
两者都在 0
的范围内至 32
.
例如:
int i = SetBitWithinRange(2,4)
将导致 i
值为 0b00...01100
最佳答案
这里有一些方法。首先,“设置 n
位,然后移位 from
”的一些变体。不过我会用 C# 回答,我对它比对 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 的右侧,它只是从零中减去零。然后在“从”部分的 1 处,您将从 1 中减去(如果 to == from
)并得到 0 作为结果,或者您将从 0 中减去 1 并一直借到 1 to
部分,这将被重置。
在撰写本文时提出的所有真正的按位方法都有其中一个缺点,这就提出了一个问题:它可以在没有缺点的情况下完成吗?
不幸的是,答案令人失望。它可以在没有缺点的情况下完成,但只能通过
- 作弊(即使用非按位元素),或
- 更多的操作,或者
- 非标准操作
以 1 为例,您可以选择前面的任何方法并添加一个特殊情况(使用 if
或三元运算符)来解决它们的缺点。
举个例子2:(未测试)
uint uppermask = (((uint)to >> 5) ^ 1) << to;
return uppermask - (1u << from);
uppermask
取 1 并将其左移 to
(像往常一样),或者如果 to == 32
,它需要一个 0 并将其左移(移动一个无关紧要的量,因为它被移动的是 0)。 .但它有点奇怪并且使用了更多的操作。
举个 3 的例子,当你移位操作数大小或更多时给出零的移位会很容易地解决这个问题。不幸的是,这种转变并不常见。
关于C:设置变量范围内所有位的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22662807/