一、整数的基础知识
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,第二步将符号位变为正号,完成了绝对值的过程,第三步此处完成了负数数字部分的转变。这样就成功求出了负数的绝对值。