一、整數的基礎知識
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,第二步將符號位變為正號,完成了絕對值的過程,第三步此處完成了負數數字部分的轉變。這樣就成功求出了負數的絕對值。