最近,我正在做一些与位操作有关的事情。到目前为止,我已经尝试了许多位操作。但是我只能进行一次手术。
假设我的整数n = 5;二进制(101),现在我想对这个int执行按位NOT运算,我认为结果是(010),但是结果是-6。
但是当我尝试n =〜(-n)时,结果为4(尽管仍然没有得到正确的输出)。请告诉我为什么显示这种行为是因为我的int不是未签名的。另外,请告诉我实现此操作的理想方法,以便获得正确的输出。我的主要动机是正确翻转位。
谢谢
您可能想要这个:
// assuming n is a 32 bit int
n = 5; // n = 00000000000000000000000000000101
n = ~n; // n = 11111111111111111111111111111010
n = n & 0x7; // n = 00000000000000000000000000000010
使用&
运算符(按位和)可屏蔽n
的第3至31位
您可以选择将最后两个语句合而为一:
n = ~n & 0x7;
int
具有多个树位,因此您必须掩盖像这样的按位求反的结果:
int flip(int n) {
// bitwise AND with 0b111 = 7, this will clear all but the last 3 bits
return ~n & 0b111;
}
得到-6的原因是,int
通常用二进制补码表示,其中-6
是所有1
位,但以010
结尾。您必须删除这些前导1
位才能获得正确的结果。
通常,我建议不要对带符号的数字使用按位运算,而应执行以下操作:
unsigned flip(unsigned n) {
return ~n & 0b111;
}
// this version works with any number of bits, not just 3
unsigned flip(unsigned n, unsigned bits) {
unsigned mask = (1 << bits) - 1;
return ~n & mask;
}
如果您不知道数字有多少位,则必须首先找到最高有效位。以最幼稚的方式,可以这样做:
unsigned log2(unsigned val)
{
unsigned result = 0;
while (val >>= 1) {
++result;
}
return result;
}
unsigned variable_flip(unsigned n) {
return flip(n, log2(n));
}
您可以找到更有效的解决方案here。
例如:
unsigned log2_debruijn(uint32_t val) {
static const unsigned MultiplyDeBruijnBitPosition[32] = {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};
// first round down to one less than a power of 2
// this step is not necessary if val is a power of 2
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
return MultiplyDeBruijnBitPosition[(val * uint32_t{0x07C4ACDD}) >> 27];
}