使用位运算求绝对值

  • Post author:
  • Post category:其他


今天看到有人说可以用位运算求绝对值,于是自己尝试推导了一下,然而没推出来。看了网上其他人的讲解,觉得这个问题很有意思,有必要记录一下。

在计算机基础课程里面我们知道,对于负数而言,原码转补码是 除符号位

取反加1

,补码转原码也是 除符号位

取反加1。

同时,如果我们求出了一个负数的原码,那么它的绝对值就很好求了,只需将这个原码的符号位取反即可(将1取反为0)。梳理一下,补码转原码时,除符号位都取反了,原码转绝对值时,符号位被取反了,那么,其实我们可以将这两次取反操作合在一起,即:对补码的

所有位

取反,然后

加1

,可得到该补码对应的

负数

的绝对值。

假设a是32位负整数,那么

  • a的符号位是1,(a >> 31) 是 111…111,一共32个1,也就是

    -1的补码


  • 和1进行异或

    相当于

    取反

    ,即 0 ^ 1 = 1,1 ^ 1 = 0,
  • x

    + 1

    相当于 x

    – (-1)

    ,x是任意数,

那么

  • 将a按位取反的算法是:a ^ (a >> 31),
  • 将a将位取反加1的算法是:(a ^ (a >> 31)) + 1 == (a ^ (a >> 31)) – (-1) == (a ^ (a >> 31)) – (a >> 31)。

对应的代码是:

int abs(int n) {
    int bits = sizeof(int) * 8 - 1;
    return (n ^ (n >> bits)) - (n >> bits);
}

其实这个算法同样适用于正整数求绝对值,因为,

假设b是32位正整数,那么

  • b的符号位是0,(b >> 31) 是 000…000,一共32个0,也就是

    0的补码


  • 和0进行异或

    相当于

    不变

    ,即 0 ^ 0 = 0,1 ^ 0 = 1,

那么

(b ^ (b >> 31)) – (b >> 31) == b。



版权声明:本文为choumin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。