仅使用位操作符的C符号函数



我正试图仅使用位操作符实现符号函数。我知道,如果我只想提取一个有符号整数的符号位,我可以这样做:(x >> 31) & 1 .

而且,我知道条件可以写成布尔表达式:

if(x) a=y else a=z等价于a = x ? y:z,可重写为:

a=( (x<<31) << 31 ) & y + ( !x << 31) >> 31) & z,假设x=1或0。

这个问题有点棘手,因为我有3个条件场景:

为正返回1,为零返回0,为负返回-1。

我在想,为了正确地做到这一点,我需要使用!运算符和!0x<nonzero #>=0, !0x0=1, !0x1=0

所以我想到了这样的东西,这是不正确的:

/*                                                                              
 * sign - return 1 if positive, 0 if zero, and -1 if negative                   
 *  Examples: sign(130) = 1                                                     
 *            sign(-23) = -1                                                    
 *  Legal ops: ! ~ & ^ | + << >>                                                                          
 */
int sign(int x) {
    return (x>>31) & -1 ) + ( !( !x >> 31 ) & 1;
}

我想我已经掌握了所有的部分,只是不太确定如何把它们组合在一起。任何帮助都是感激的。

谢谢。

位黑客页面建议这样表达:

sign = (v != 0) | (v >> 31);

可以不使用!=重写,如下所示:

sign = (!!v) | (v >> 31);

(demo on ideone).

我更喜欢这个不使用位操作的表达式(来自同一页)。

sign = (v > 0) - (v < 0);

如果右移是二进制的,而不是算术的,这个也可以工作:

unsigned int x;
static_assert (sizeof(x) == 4);
(~ (!!x)) + 1 + ( ( (x+0x7FFFFFFF) & 0x80000000 )  >> 30 )

(~ (!!x)) + 1 + ( ( !!( (x+0x7FFFFFFF) & 0x80000000 ) ) << 1 )

解释:

(~ (!!x)) + 1为x==0提供0,否则为-1。

( ( (x+0x7FFFFFFF) & 0x80000000 ) >> 30 )为x>0提供2,否则为0。

最新更新