我有以下功能
int sign(int x) {
int sign = (x >> 31);
sign = sign | 1;
return sign;
}
我希望有以下几点:
- 为负数返回 -1(第一行)
- 返回 1 为正数(第二行)
- 返回 0 表示零
我被困在最后一项上。如果 x 为零,如何仅使用按位运算符返回零?
我有以下功能
int sign(int x) {
int sign = (x >> 31);
sign = sign | 1;
return sign;
}
我希望有以下几点:
我被困在最后一项上。如果 x 为零,如何仅使用按位运算符返回零?
不错的小拼图。假设您有 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;
}
用这个
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
可能 >= 到类型格式 (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
以避免未定义的行为
你也可以使用这个。它与我之前的答案具有相同的逻辑
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;
}