我有以下功能
int sign(int x) {
int sign = (x >> 31);
sign = sign | 1;
return sign;
}
我希望以下内容:
我坚持最后一项。如果x为零,如何仅使用按位运算符返回零?
答案 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!=0
则x==0
我们只需要y==0
(y
)的前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;
}