Java Integer.highestOneBit(i)代碼

、在寫代碼的過程中,偶爾使用到了
  1. Integer.highestOneBit(i)  
這個函數調用。使用的第一感覺就是這個函數是幹什麼用的,通過查看文檔得知,這個函數的作用是取 i 這個數的二進制形式最左邊的最高一位且高位後面全部補零,最後返回int型的結果。

首先來補充一點背景知識。

1、在計算機系統中,數值一律使用補碼來表示和存儲。主要原因是使用補碼可以將符號位和其它位統一處理;同時,減法也可按照加法來處理。另 外,   兩個用補碼錶示的數相加時,如果最高位(符號位)有進位,則進位被捨棄。
- 補碼與原碼的轉換過程幾乎相同。
    - 數值的補碼錶示(分兩種)
        - 正數的補碼:與原碼相同
        - 負數的補碼:符號位位1,其餘位位該數絕對值的原碼按位取反;然後整個數加1
    - 已知一個數的補碼,求原碼的操作分爲兩種情況
        - 如果補碼的符號位“0”,表示是一個正數,所以補碼就是該數的原碼
        - 如果補碼的符號位爲“1”,表示是一個負數,求原碼的操作可以是:符號位位1,其餘各位取反,然後整個數加1。
2、移位運算符就是在二進制的基礎上對數字進行平移。Java按照平移的方向和填充數字的規則分爲三種:<<左移,>>帶符號右移 和>>>無符號右移。
3、 在Java的移位運算中,byte、short和char類型移位後的結果會變成int類型,對於byte、short、char和int進行移位時,對於char、short、char和int進行移位操作時,規定實際移動的次數是移動次數和32的餘數,也就是移位33次和移位1次得到的結果相同。移動long型的數值時,規定實際移動的次數是移動次數和64的餘數,也就是移動65次移位1次得到相同的結果。
    (1) <<  運算規則:按二進制形式吧所有的數字向左移動對應的位數,高位移出(捨棄),低位的空位補零。
    語法格式:
         需要移位的數字<<移位的次數
         例如:4<<2 ,則是將數字4左移2位
     計算過程
         4<<2
        Java中一個int數佔四個字節,那麼4的二進制數字爲00000000 00000000 00000000 00000100,然後把該數字左移兩位。其它的數字都朝右平移兩位,最後在低位(右側)的兩個空位補零。則得到的最終結果是00000000 00000000 00000000 00010000,即轉換爲十進制數16。
         在數字沒有溢出的前提下,對於正數和負數,左移一位都相當於乘以2的1次方,左移n位就相當於乘以2的n次方。
         在溢出的前提前,則不符合這個規律。讀者可以嘗試輸出(long)1610612736*4和1610612736<<2這兩個結果進行比對。
    (2)>>運算規則:按二進制形式吧所有的數字都向右移動對應的位置,低位移出(捨棄),高位的空位補符號位,即正數補零,負數補1。
     語法格式:
         需要移位的數字>>移位的次數
         例如:-4>>2和4>>2,則是將數字 -4和4右移2位
     計算過程
         4>>2
         Java中一個int數佔四個字節,同樣4的二進制爲00000000 00000000 00000000 00000100,然後把該數字右移兩位。其它的數字都朝左平移兩位,最後在高位補符號位(該數是正數,全補零),得到的結果是00000000 00000000 00000000 00000001,即使十進制的1。數學意義就是右移移位相當於除2,右移n位相當於除以2的n次方。
        4>>2
         由於負數在計算機中是以補碼的形式存儲的,那麼-4的二進制爲11111111 11111111 11111111 11111100,然後把該數字右移兩位,其它數字都朝左平移兩位,最後在高位補符號位(該數是負數,全補一),得到的結果是11111111 11111111 11111111 11111111(補碼格式),即是十進制的-1。
    (3)>>>運算規則:按二進制形式吧所有的數字向右移動對應的位數,低位移出(捨棄),高位的空位補零。正數運算結果與帶符號右移相同,對於負數來說則不同。
         對於4>>>2和-4>>>2運算,可以通過上述例子進行類推。

瞭解了Java的位運算之後,來看下  Integer.highestOneBit (i) 這個函數的實現代碼:
  1. publicstaticinthighestOneBit(int i) {  
  2.      // HD, Figure 3-1  
  3.      i |= (i >>  1);  
  4.      i |= (i >>  2);  
  5.      i |= (i >>  4);  
  6.      i |= (i >>  8);  
  7.      i |= (i >> 16);  
  8.      return i - (i >>> 1);  
  9.  }  

1、第一步的作用是把最高位1右移移位,並與原數據按位取或。那麼這就使得最高位和它的下一位是連續兩個1。
2、第二步的作用是把剛剛移位得到連續兩個1繼續右移兩位並與原數據按位取或。那麼這就使得最高兩位和它的下兩個連續位組成四個連續的1。
3、 以此類推,最終得到的i是從開始的最高位到結束全是1。並減去i不帶符號的右移一位,即可得到一個int數據的最高位的值。
4、上述情況是針對於i不爲零和負數的情況,如果i爲零,那麼得到的結果始終爲零。如果i位負數,那麼得到的結果始終是-2147483648。即等於Integer.MIN_VALUE。(原因在於負數的最高位始終爲1,即是負數的符號位)
 
此函數的最重要理解點在與要始終把握二進制的最高位進行運算處理,那麼對於函數中的右移一位、兩位、四位、八和十六位就好理解了。同理,對於long類型的取最高位運算應該需要加一條語句 i|=(i>>32); 原因在於long類型在Java中是64位的。
Long類型的hightestOneBit(i)代碼如下:
  1. public static long highestOneBit(long i) {  
  2.     // HD, Figure 3-1  
  3.     i |= (i >>  1);  
  4.     i |= (i >>  2);  
  5.     i |= (i >>  4);  
  6.     i |= (i >>  8);  
  7.     i |= (i >> 16);  
  8.     i |= (i >> 32);  
  9.     return i - (i >>> 1);  
  10. }  
發佈了4 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章