使用位运算求整数的绝对值

一、整数的基础知识

1. int在内存中占4个字节,32位。

2.int在内存中以补码的形式表示。

1)正数的原码、反码、补码都是一样的。

2)负数的补码=负数的原码除符号位外取反,然后加1

所以,在内存中,-1和1的表示差别不仅仅在符号位。

 

二、右移运算符

 右移运算符指高位按符号位进行填充。即正数用0填充,负数用1填充。

因此,若定义int x,那么 x>>31,若x为正数,结果是0,若x为负数,结果是0Xffffffff,也就是-1的补码。因为整数在内存中就是用补码表示,所以,0Xffffffff就是-1。

 

三、异或运算符

异或可以理解为不进位加法,即1+1 = 0, 0+0=0,1+0=1。

由上可知,任意整数与0异或,结果还是整数本身,与0Xffffffff异或,则是将该整数连同符号位在内一并取反。

上面的知识是使用位运算求整数绝对值时需要用到的。下面再补充一些异或运算的其他知识。

 

异或运算的四个性质:

1)交换律

可任意交换运算因子的位置,结果不变。  即a^b = b^a

2)结合律

(a^b)^c  =  a^(b^c)

3)对于任何数x,都有x^x = 0, x^0 = x, 即同自己求异或为0,同0求异或为自己。

4)自反性 

连续和同一个因子做异或运算,最终结果为自己。

A^B^B = A^0 = A

 

四、使用位运算求整数的绝对值

原理:

负数的补码原码转补码是 除符号位取反加1,补码转原码也是 除符号位取反加1。如果我们求出了一个负数的原码,那么它的绝对值就是将这个原码的符号位取反即可(将1取反为0)。

即:补码转原码时,除符号位都取反了,原码转绝对值时,符号位被取反了,那么,将这两次取反操作合在一起,即:对补码的所有位取反,然后加1,可得到该补码对应的负数的绝对值。

 

C语言代码:

int abs(int a)
{
    int iMask = a>>31;
    a = a^iMask-iMask;
    return a;
}

 

或者:

int abs(int a)
{
    int iMask = a>>31;
    a = a^iMask;
  a = a-
iMask;
return a; }

 

代码解析:

当a为正数时:第一步,iMask=0,第二步,a异或0,结果a还是本身,第三步,a-0,结果还是a。符合正数的绝对值是其本身,代码成立。

当a为负数时

第一步,iMask=0Xffffffff,即-1的补码,因为整数在内存中用补码表示,所以iMask实际上就是-1;

第二步,a异或0Xffffffff,即连同符号位在内对a取反,此时,符号位1变成0,即负号变成正号。

第三步,a-iMask = a-(-1) = a+1,负数的补码 = 除符号位外取反加1,第二步将符号位变为正号,完成了绝对值的过程,第三步此处完成了负数数字部分的转变。这样就成功求出了负数的绝对值。

 

 

 

posted on 2021-01-07 17:01  南枝  阅读(1819)  评论(0编辑  收藏  举报