1

我有以下功能

int sign(int x) {

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

}

我希望有以下几点:

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

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

4

3 回答 3

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;
}
于 2013-04-23T16:07:02.753 回答
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);

但是当我们用 左移时我们必须小心1x因为x可能 >= 到类型格式 (32) 的大小并且x可能是 negatif 并且对于这两种情况它都是未定义的行为。

所以为了避免上述问题,我将我们的 32 位 (the x) 拆分为 7 个块,每个块包含 5 个位,除了最后一个包含 2 个位,然后我|为所有块做了一个

y=(bloc1|bloc2|bloc3|bloc4|bloc5|bloc6|bloc7) 

所以如果x!= 0那时y!=0

如果x==0那时y==0

我们只需要取y( &0x1F) 的前 5 位。在这里,我确定这y不是否定的,并且y<32

然后x我可以换位而不是换位y以避免未定义的行为

于 2013-04-23T17:12:44.970 回答
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;
}
于 2013-04-23T18:51:26.380 回答