如何清除最重要的位

本文关键字:最重要的 清除 何清除 | 更新日期: 2023-09-27 18:11:31

如何将整型数的最高有效位从1改为0?例如,我想将01101更改为0101。

如何清除最重要的位

编辑:简化(并解释)答案

如果你的只是目标是将最高有效位设置为0,那么我下面给出的答案是多余的。

最后一位代码构建了一个位掩码,该掩码包含了数字中所有的位。

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)

我给出的原始答案

对于这类问题,我经常参考这篇文章:

"Bit Twiddling Hacks"

你想要的特定部分被称为"查找整数log以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);

进行此类位操作的最简单方法是使用左移操作符(<<)。

(1 << 3) = 100b, (1 << 5) = 10000b

则使用想要更改某位的值并使用
| (OR)如果您想将其更改为1或
,~ (AND NOT)如果你想把它改成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);