如何使用按位运算返回0?

时间:2013-04-23 13:24:22

标签: c bit-manipulation

我有以下功能

int sign(int x) {

  int sign = (x >> 31);
  sign = sign | 1;
  return sign;

}

我希望以下内容:

  • 返回-1表示负数(第一行)
  • 返回1表示正数(第二行)
  • 返回0表示零

我坚持最后一项。如果x为零,如何仅使用按位运算符返回零?

3 个答案:

答案 0 :(得分:2)

不错的小谜题。假设您有32位整数:

int sign( int x )
{
   // if any bit is on, all bits are on. else zero.
   int lowBit = x;
   lowBit |= lowBit >> 16;
   lowBit |= lowBit >> 8;
   lowBit |= lowBit >> 4;
   lowBit |= lowBit >> 2;
   lowBit |= lowBit >> 1;
   lowBit &= 1;

   int signBit = x & 0x80000000;
   signBit |= signBit >> 16;
   signBit |= signBit >> 8;
   signBit |= signBit >> 4;
   signBit |= signBit >> 2;
   signBit |= signBit >> 1;
   signBit &= 0xFFFFFFFE;

   return signBit | lowBit;
}

以下是它的工作原理。我将解释4位数字,但解释概括。您必须从三类位模式进行映射:

0000    -> 0000
0xxx    -> 0001
1yyy    -> 1111

其中x可以是除000以外的任何东西,yyy可以是任何东西。

首先,如果寄存器中的任何位为1,则需要1位,否则为0。所以我们'涂抹'寄存器,这样如果任何位为高,则所有位都为高,并且我们将该位保留为结果中低位的值。

然后我们'涂抹'符号位。最后我们'或'他们在一起。

读者练习:如果你有32位整数,但是有64位寄存器,你可以将操作次数减半。

更新:总是可以做得更好(未经测试):

int sign( int x )
{
   int lowBit = !!x;  // double ! operator, wtf? yes...

   int signBit = x & 0x80000000;
   signBit |= signBit >> 16;
   signBit |= signBit >> 8;
   signBit |= signBit >> 4;
   signBit |= signBit >> 2;
   signBit |= signBit >> 1;
   signBit &= 0xFFFFFFFE;

   return signBit | lowBit;
}

答案 1 :(得分:0)

使用此

int sign(int x) {

  int sign = (x >> 31);
  sign = sign | (~(1<<((x|(x>>5)|(x>>10)|(x>>15)|(x>>20)|(x>>25)|(x>>30))&0x1F))&0x1);
  return sign;

}

我们的想法是左移1并计算x

因此,如果x==0,则第一位将保留1

如果x!=0,则第一位将更改为0

然后是sign = sign | (~(First bit))

它相当于

sign = sign | (~(1<<x) & 0x1);

但是当我们使用1离开x时我们必须要小心,因为x可能是&gt; =类型格式的大小(32)和{{ 1}}可以是negatif,对于这两种情况,它都是未定义的行为。

为了避免上述问题,我将32位(x)拆分为7个块,每个块包含5位,除了最后一个包含2位,然后我为所有人创建了x blok

|

所以,如果y=(bloc1|bloc2|bloc3|bloc4|bloc5|bloc6|bloc7) ,那么x!= 0

如果y!=0x==0

我们只需要y==0y)的前5位。在这里,我确信&0x1F不是否定,而y

然后转而不是y<32我可以使用x转换以避免未定义的行为

答案 2 :(得分:0)

你也可以使用它。它与我以前的答案具有相同的逻辑

int sign(int x) {
  int y = x;
  y |= y >> 16;
  y |= y >> 8;
  y |= y >> 4;
  y &= 0xF;

  int sign = (x >> 31);
  sign = sign | (~(1<<y) & 0x1);
  return sign;
}