Java千問:Java位運算經典應用(一)

很多人認爲位運算在實際開發過程中並沒什麼用,學習位運算也只是爲了應付面試。這種想法是錯誤的,接下來我們就通過幾篇連載文章介紹一下位運算在實際開發過程中的幾個經典應用實例。如果對位運算規則掌握還不是很熟練,可以先閱讀《Java千問:Java語言位運算符詳解》。這篇文章不僅詳細講解了Java位運算的基本規則和一些常用的運算定律,同時還在文中提到了一些常用的位運算實際應用,比如可以用位運算操作的方式快速把某個變量所在的內存單元清零,或者位運算的方式實現某個變量快速倍增等等。但文中所這提到的這幾個實際應用比較簡單,本次連載文章將爲大家講述的是更加複雜和實際的應用經典案例。此外,爲獲得更好的閱讀效果,請各位讀者在讀本文之前先熟練掌握”補碼”的計算規則。

一、判斷整數的奇偶性

按照傳統的思路,判斷一個整數的奇偶性是通過用這個數與2求模,看運算結果是否爲0。學了位運算符以後,我們可以換一種思路來考慮問題。我們知道:Java語言中,所有數字存儲在內存中,都要先轉換成補碼的形式。任何一個偶數用補碼表示出來後,它的最後一個二進制位都是0,而奇數補碼的最後一個二進制位都是1。所以,我們可以通過判斷這個整數的補碼的最後一位二進制數是0還是1,來判斷這個數是偶數還是奇數。判斷的方法就是用這個數與1進行按位與的操作,如果結果爲0,那麼這個數就是偶數,否則就是奇數。如果大家不理解這個算法的原理,請看下圖:

Java千問:Java位運算經典應用(一)
爲了方便表述,我們把要判斷奇偶性的數字稱爲a。圖中,以橫線爲界,分別展示了a爲偶數和奇數的情況下,與數字1進行按位與操作的結果。其中,上面的二進制串是a的補碼,下面二進制串是數字1的補碼。可以看到,數字1被轉換成補碼之後,總共有32位,其中前31位都是0,最後1位的值是1。這就導致a補碼的前31位無論是0還是1,與數字1的補碼進行按位與運算,運算結果的前31位都只能是0,決定最終運算結果的就只有a補碼最右邊的那個二進制位。如果最右邊那一位是0,那麼a就是偶數,a與1按位與運算的最終結果是數字0。反過來,如果最右邊那一位是1,那麼a就是奇數,a與1按位與運算的最終結果是數字1。因此我們只要看一下a與數字1進行按位與運算的結果就知道a的奇偶性了。具體的程序實現如下:

Java千問:Java位運算經典應用(一)

二、求絕對值

常規算法求絕對值的思路是:首先判斷一個數a是否>=0,如果a>=0,則返回a本身,否則返回a的相反數。這個過程包含判斷和選擇兩個步驟。如果使用位運算符來實現求絕對值,可以省略掉判斷的步驟,直接返回運算結果。下面來講解一下使用位運算符求絕對值的基本原理。我們知道:任何一個二進制位上的數,與0進行異或運算,運算的結果都與這個二進制位上的數相同。把這個結論擴展一下,從原來某個數的單獨的一個二進制位擴展到這個數字本身,可以得出另外兩個結論,第一個結論:任何一個整數與0進行異或運算後依然保持不變。如果小夥伴不理解的話,請看下圖,我們以數字5作爲例子分析講解:
Java千問:Java位運算經典應用(一)
另一個結論:任何一個整數與-1進行異或運算後再加上1,得到的結果就是這個數的相反數。如果不理解的話,還是看下圖,仍然是以數字5分析講解:
Java千問:Java位運算經典應用(一)
以上兩個結論中,第一個結論比較容易理解。我們簡單的解釋一下第二個結論的原理。第二個結論能夠成立的關鍵就在於,數字-1用補碼的形式表示出來,恰好是一個32位全爲1的二進制串。這個二進制串與任何一個其他二進制串進行按位異或運算,都可以達到”取反”的效果,而按照補碼的計算規則,一個正數按位取反後再加1,得到的就是它相反數。比如圖中的數字5,按位取反之後,再加1得到的就是-5。
至此,我們已經知道怎樣通過位運算的方式獲得一個數的相反數了。在《Java千問:Java語言位運算符詳解》一文中還講過:int類型的正數經過帶符號右移31位之後,得到的必然是0,而負數經過帶符號右移31位得到的是-1。我們就可以通過右移所得到的這個0或者-1,判斷出這個數是正數還是負數。知道數字的正負屬性,然後再用位運算的方式得到這個數本身或者是它的相反數,就能求出這個數的絕對值。按照這個思路,我們就可以來編寫求絕對值的程序了,程序如下:
Java千問:Java位運算經典應用(一)
示例程序中的變量a是int型,如果改爲long型,對a帶符號右移63位也可有相同的運算效果。

(未完待續...)
如想系統學習Java編程,歡迎觀看我在本站的視頻課程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章