如何将 int 中的最高有效位从 1 更改为 0?例如,我想将 01101 更改为 0101。
编辑:简化(并解释)答案
如果您的唯一目标是将最高有效位设置为零,那么我在下面给出的答案就太过分了。
最后一段代码构造了一个位掩码,其中包含数字中的所有位。
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
这是它对给定的 32 位无符号整数执行的一系列计算:
mask = originalValue
mask: 01000000000000000000000000000000
mask |= mask >> 1: 01100000000000000000000000000000
mask |= mask >> 2: 01111000000000000000000000000000
mask |= mask >> 4: 01111111100000000000000000000000
mask |= mask >> 8: 01111111111111111000000000000000
mask |= mask >> 16: 01111111111111111111111111111111
由于它会向右移位(不会回绕),因此它永远不会将高于最高有效位的位设置为 1。由于它使用逻辑
or
,因此您永远不会显式地将任何尚未为零的值设置为零。
从逻辑上讲,这将始终创建一个位掩码,填充整个
uint
,直到并包括最初设置的最高有效位,但不能更高。
从该掩码中,很容易将其缩小以包含所有但是最初设置的最重要位:
mask = mask >> 1: 00111111111111111111111111111111
然后只需对原始值执行逻辑
and
,它会将数字中的所有最高有效位设置为零,直到并包括原始值的最高有效位:
originalValue &= mask: 00000000000000000000000000000000
我在这里使用的原始数字很好地显示了掩模构建过程,但它并没有很好地显示最后的计算。让我们用一些更有趣的示例值(问题中的值)来进行计算:
originalValue: 1101
mask = originalValue
mask: 00000000000000000000000000001101
mask |= mask >> 1: 00000000000000000000000000001111
mask |= mask >> 2: 00000000000000000000000000001111
mask |= mask >> 4: 00000000000000000000000000001111
mask |= mask >> 8: 00000000000000000000000000001111
mask |= mask >> 16: 00000000000000000000000000001111
mask = mask >> 1: 00000000000000000000000000000111
这就是您正在寻找的价值:
originalValue &= mask: 00000000000000000000000000000101
既然我们可以看到它的工作原理,让我们把最终的代码放在一起:
uint SetHighestBitToZero(uint originalValue)
{
uint mask = originalValue;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
mask = mask >> 1;
return originalValue & mask;
}
// ...
Console.WriteLine(SetHighestBitToZero(13)); // 1101
5
(即0101)
我原来的答案
对于这类问题,我经常参考这篇文章:
您想要的特定部分称为“查找整数的以 2 为底的整数对数(也称为最高位集的位置)”。
这是一系列解决方案中的第一个(每个都比前一个更优化):
http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
文章中最终的解决方案是(转换为C#):
uint originalValue = 13;
uint v = originalValue; // find the log base 2 of 32-bit v
int r; // result goes here
uint[] MultiplyDeBruijnBitPosition =
{
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
v |= v >> 1; // first round down to one less than a power of 2
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
r = (int)MultiplyDeBruijnBitPosition[(uint)(v * 0x07C4ACDDU) >> 27];
一旦找到最高设置位,只需将其屏蔽即可:
originalValue &= ~(uint)(1 << r); // Force bit "r" to be zero
受到 Merlyn Morgan-Graham 的回答的启发
static uint fxn(uint v)
{
uint i = v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return (v >> 1) & i;
}
您可以使用类似以下内容(未经测试):
int a = 13; //01101
int value = 0x80000000;
while ((a & value) != value)
{
value = value >> 1;
}
if (value > 0)
a = a ^ value;
int x = 0xD; //01101
int wk = x;
int mask = 1;
while(0!=(wk >>= 1)) mask <<= 1;
x ^= mask; //00101
如果您知道类型的大小,则可以移出这些位。 您也可以轻松地将其放入 BitArray 中并翻转 MSB。
示例1:
short value = -5334;
var ary = new BitArray(new[] { (value & 0xFF00) >> 8 });
ary.Set(7, false);
示例2:
short value = -5334;
var newValue = Convert.ToInt16((value << 1) >> 1);
// Or
newValue = Convert.ToUInt16(value);
int clearMostSignificantBit(int num) {
uint8_t shift = 0;
int temp = num;
while (temp != 0) {
temp >>= 1;
shift++;
}
return num & ~(1 << (shift - 1));
}
执行此类按位运算的最简单方法是使用左移运算符(<<).
(1 << 3) = 100b
、(1 << 5) = 10000b
等
然后你使用一个你想要改变某个位的值并使用
| (或)如果您想将其更改为 1 或
& ~(而不是)如果您想将其更改为 0。
像这样:
int a = 13; //01101
int result = a | (1 << 5); //gives 11101
int result2 = result & ~(1 << 5); //gives 01101
如果您将其视为整数,那么代码的结果将始终显示而没有零。可能是字符串操作会输出您想要的东西,但不确定这将如何帮助您。使用如下所示的字符串:
string y = "01101";
int pos = y.IndexOf("1");
y = y.Insert(pos, "0");
y = y.Remove(pos + 1, 1);