使用位运算符在C中实现sign函数

4

我正在尝试使用位运算符来实现符号函数。我知道如果只想提取有符号整数的符号位,可以这样做:(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。

然而,这个问题变得有点棘手,因为我有三种条件场景:
如果是正数则返回1,如果是零则返回0,如果是负数则返回-1。

我认为为了做到这一点,我需要使用!运算符和!0x<非零数>=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;
}

我觉得我已经掌握了所有的要点,但不太确定如何将它们组合在一起。非常感谢您的帮助。

谢谢。


2
使用编译器来解决作业问题并不一定是错误的。 :) - Greg Hewgill
3
尝试那样做有点愚蠢。 (x > 0 ? 1 : x < 0 ? -1 : 0) 是一个非常好的、可移植且易读的解决方案。任何更复杂的东西都是无意义的。 - gnasher729
3
程序员遵循问题约束条件。 - Hunter McMillen
1
你知道位运算技巧吗?https://graphics.stanford.edu/~seander/bithacks.html。我的评论只是一种贡献,而不是答案。 - JayInNyc
1
使用 (x >> 31) & 1 提取符号位,根据 C 实现和 int 类型中值位的数量,可能是实现定义、未定义行为或错误的。 - gnasher729
显示剩余5条评论
2个回答

12

这个位运算技巧页面提供了以下表达式:

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

可以像下面这样重写它,而不使用 !=
sign = (!!v) | (v >> 31);

(这里是ideone上的演示).

我更喜欢不使用位操作的这个表达式,尽管它也来自同一页。

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

3
前两个非常不便携,最后一个完全正常且正确。额外���好处是它适用于所有实数类型,包括有符号、无符号、所有大小和浮点数。 - gnasher729
@gnasher729 前两个可以使用链接页面中的表达式(即 sizeof(int)*BITS_PER_BYTE-1,其中 BITS_PER_BYTE 定义了目标计算机上字节中位数的数量)来使其更加可移植。我最喜欢最后一个,这就是为什么我提到它,尽管我认为它违反了 OP 的规则。 - Sergey Kalinichenko
为什么不使用标准的CHAR_BIT,而是使用BITS_PER_BYTE - Deduplicator
谢谢@dasblinkenlight。第二个方程式就是我要找的。有没有一种系统化的方法来得出这些解决方案?对我来说太复杂了。 - user1527227
1
v >> 31 会导致实现定义的行为。 - M.M
显示剩余5条评论

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。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接