【问题标题】:sign function in C using bit operators only仅使用位运算符在 C 中签名函数
【发布时间】:2014-07-20 23:22:09
【问题描述】:

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

我想我拥有所有的部分,但不太确定如何将它们组合在一起。任何帮助表示赞赏。

谢谢。

【问题讨论】:

  • 使用编译器得到作业问题的答案不一定是错误的。 :)
  • 这是一个相当愚蠢的尝试。 (x > 0 ? 1 : x
  • 程序员遵循问题约束。
  • 你知道小玩意儿吗? graphics.stanford.edu/~seander/bithacks.html。我的评论只是一个贡献,而不是一个答案。
  • OP:使用 (x >> 31) & 1 来提取符号位是,取决于 C 实现和 int 中值位的数量,实现定义或未定义行为,或错了。

标签: c bit-manipulation


【解决方案1】:

bit hacks page 建议这个表达式:

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

不用!=也可以这样重写:

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

(demo on ideone).

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

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

【讨论】:

  • 如果 v == 0 则返回 1。
  • 前两个非常不便携,最后一个完全正确。还有一个额外的好处是它适用于所有实类型,包括有符号、无符号、所有大小和浮点。
  • @gnasher729 前两个可以通过链接页面中的表达式减少不可移植性(即sizeof(int)*BITS_PER_BYTE-1,其中BITS_PER_BYTE 定义目标计算机上一个字节中的位数) .我最喜欢最后一个,这就是我提到它的原因,尽管我认为它违反了 OP 的规则。
  • BITS_PER_BYTE?为什么不是标准的CHAR_BIT
  • v &gt;&gt; 31 导致实现定义的行为
【解决方案2】:

如果右移位是二进制移位而不是算术移位,则此移位也有效:

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) &amp; 0x80000000 ) &gt;&gt; 30 ) 为 x>0 提供 2,否则为 0。

【讨论】:

    猜你喜欢
    • 2011-10-16
    • 1970-01-01
    • 2012-10-14
    • 2013-10-13
    • 2014-02-21
    • 1970-01-01
    • 2015-11-27
    • 1970-01-01
    • 2012-04-16
    相关资源
    最近更新 更多