java移位運算、邏輯運算、異或及取反運算

最近看源碼,複習了下基礎運算知識,做下記錄,一些表述與其他或者官方有些詫異,純屬個人心得,歡迎參考借鑑,指出錯誤,共勉。

    public static void main(String[] args) {

        //正數左移: 簡單的理解爲 移幾位就在右邊加幾個0依次計算
        System.out.println(3 << 1);//6 3乘以2的1次方 11 ==> 110 [4+2+0]
        System.out.println(3 << 2);//12 3乘以2的2次方 11 ==> 1100 [8+4+0+0]
        System.out.println(3 << 3);//24 3乘以2的3次方 11 ==> 11000 [16+8+0+0+0]
        System.out.println(3 << 4);//48 3乘以2的4次方 11 ==> 110000 [32+16+0+0+0+0]
        System.out.println(3 << 5);//96 3乘以2的5次方 11 ==> 1100000 [64+32+0+0+0+0+0]

        //負數左移: 先獲取補碼,低位補0,高位超出捨棄,再取移位後的反碼,再取補碼[最終結果],以上操作符號位都不變
        //原碼 ==> 反碼 ==> 補碼 ==> 移位 ==> 再取反碼 ==> 再取補碼(最終結果)
        System.out.println(-7 << 3);  //-56
        /*
        原碼 1000 0000 0000 0000 0000 0000 0000 0111
        反碼 1111 1111 1111 1111 1111 1111 1111 1000 [符號位不變,按位取反]
        補碼 1111 1111 1111 1111 1111 1111 1111 1001 [符號位不變,反碼+1]
        移位 1111 1111 1111 1111 1111 1111 1100 1000 [*符號位不變,高位超出位捨棄,低位補0]
   再取反碼  1000 0000 0000 0000 0000 0000 0011 0111 [符號位不變,按位取反]
   再取補碼  1000 0000 0000 0000 0000 0000 0011 1000 [符號位不變,反碼+1]
         */

        System.out.println(-297 << 5); //-9504
        /*
        原碼 1000 0000 0000 0000 0000 0001 0010 1001
        反碼 1111 1111 1111 1111 1111 1110 1101 0110 [符號位不變,按位取反]
        補碼 1111 1111 1111 1111 1111 1110 1101 0111 [符號位不變,反碼+1]
        移位 1111 1111 1111 1111 1101 1010 1110 0000 [*符號位不變,高位超出位捨棄,低位補0]
   再取反碼  1000 0000 0000 0000 0010 0101 0001 1111 [符號位不變,按位取反]
   再取補碼  1000 0000 0000 0000 0010 0101 0010 0000 [符號位不變,反碼+1]
         */

        //正數右移(有符號右移): 簡單的理解爲 移幾位 左邊就刪幾位0依次計算
        System.out.println(96 >> 1);//48 96除以2的1次方 1100000 ==> 0110000 [0+32+16+0+0+0+0]
        System.out.println(96 >> 2);//24 96除以2的2次方 1100000 ==> 0011000 [0+0+16+8+0+0+0]
        System.out.println(96 >> 3);//12 96除以2的3次方 1100000 ==> 0001100 [0+0+0+8+4+0+0]
        System.out.println(96 >> 4);//6 96除以2的4次方 1100000 ==> 0000110 [0+0+0+0+4+2+0]
        System.out.println(96 >> 5);//3 96除以2的5次方 1100000 ==> 0000011 [0+0+0+0+0+2+1]


        //負數右移 : 獲取反碼 => 補碼 => 移位[符號位不變,高位補1,低位超出位捨棄] => 再取移位後的反碼 =>取移位後的補碼
        System.out.println(-56 >> 3); //-7
        /*
          原碼 1000 0000 0000 0000 0000 0000 0011 1000
          反碼 1111 1111 1111 1111 1111 1111 1100 0111 [符號位不變,按位取反]
          補碼 1111 1111 1111 1111 1111 1111 1100 1000 [符號位不變,反碼+1]
          移位 1111 1111 1111 1111 1111 1111 1111 1001 [*符號位不變,高位補1,低位超出位捨棄]
     再取反碼  1000 0000 0000 0000 0000 0000 0000 0110 [符號位不變,按位取反]
     再取補碼  1000 0000 0000 0000 0000 0000 0000 0111 [符號位不變,反碼+1](最終結果)
         */

        System.out.println(-139 >> 5); //-5
        /*
          原碼 1000 0000 0000 0000 0000 0000 1000 1011
          反碼 1111 1111 1111 1111 1111 1111 0111 0100 [符號位不變,按位取反]
          補碼 1111 1111 1111 1111 1111 1111 0111 0101 [符號位不變,反碼+1]
          移位 1111 1111 1111 1111 1111 1111 1111 1011 [*符號位不變,高位補1,低位超出位捨棄]
     再取反碼  1000 0000 0000 0000 0000 0000 0000 0100 [符號位不變,按位取反]
     再取補碼  1000 0000 0000 0000 0000 0000 0000 0101 [符號位不變,反碼+1](最終結果)
         */

        //正數無符號右移
        //有符號右移:正數的符號位爲0,移動時,符號位不動,高位補0
        //無符號右移:高位補0,符號位跟隨移動,符號位移動後也未0,
        //其實和有符號位移所得結果是一樣的,所以宏觀上將,正數的有符號位移和無符號位移是沒啥區別的
        System.out.println(200 >> 5); //6
        /*
          原碼 [0]000 0000 0000 0000 0000 0000 1100 1000
          移位 [0]000 0000 0000 0000 0000 0000 0000 0110
         */
        System.out.println(200 >>> 5); //6
        /*
          原碼 [0]000 0000 0000 0000 0000 0000 1100 1000
          移位 0000 0[0]00 0000 0000 0000 0000 0000 0110
         */

        //負數無符號右移
        System.out.println(-200 >>> 5); //134217721
        /*
        原碼 1000 0000 0000 0000 0000 0000 1100 1000
        反碼 1111 1111 1111 1111 1111 1111 0011 0111 [符號位不變,按位取反]
        補碼 1111 1111 1111 1111 1111 1111 0011 1000 [符號位不變,反碼+1]
        移位 0000 0111 1111 1111 1111 1111 1111 1001 [*符號位也要偏移, 高位補符號位0, 低位超出位數捨棄](符號位變爲0,爲正數,三碼合一,不用繼續轉換)(最終結果)
         */

        System.out.println(-9 >>> 4); //268435455
        /*
        原碼 1000 0000 0000 0000 0000 0000 0000 1001
        反碼 1111 1111 1111 1111 1111 1111 1111 0110 [符號位不變,按位取反]
        補碼 1111 1111 1111 1111 1111 1111 1111 0111 [符號位不變,反碼+1]
        移位 0000 1111 1111 1111 1111 1111 1111 1111 [*符號位也要偏移, 高位補符號位0, 低位超出位數捨棄](符號位變爲0,爲正數,三碼合一,不用繼續轉換)(最終結果)
         */

        //或運算 & 規則 :都爲1時才爲1
        System.out.println(5 | 6); //值:7
        /* 5: 101
           6: 110
        或值: 111 ==> [4+2+1] ==> 7
         */
        System.out.println(520 | 20); //值:540
        /* 520: 1000001000
            20:   0000010100
        或值:   1000011100 ==> [512+0+0+0+0+16+8+4+0+0] ==>  540
         */

        //與運算 | 規則:有一個爲1,則爲1
        System.out.println(5 & 6); //值:7
        /* 5: 101
           6: 110
        與值: 100 ==> [4+0+0] ==> 4
         */
        System.out.println(520 & 20); //值:0
        /* 520: 1000001000
            20: 0000010100
        或值:   0000000000 ==> [0+0+0+0+0+0+0+0+0+0] ==>  0
         */

        System.out.println(88 & 66); //值:0
        /* 88: 1011000
           66: 1000010
         或值: 1000000 ==> [64+0+0+0+0+0+0] ==>  64
         */

        //異或運算  ^ 規則:不同爲1(左邊補0不做計算)
        System.out.println(5 ^ 6); //值:3
        /* 5: 101
           6: 110
       異或值: 011 ==> [0+2+1] ==> 3
         */
         System.out.println(520 ^ 20); //值:540
        /* 520: 1000001000  => 0111110111
            20: 0000010100  =>      01011
         異或值: 1000011100 ==> [512+0+0+0+0+16+8+4+0+0] ==>  540
         */

         System.out.println(88 ^ 66); //值:0
        /* 88: 1011000
           66: 1000010
        異或值: 0011010 ==> [0+0+16+8+0+2+0] ==>  26
         */

        //取反運算 ~ 規則:按位取反
        // 正數步驟 原碼取反(值1) ==> 值1-1[符號位不變](值2) ==> 再取反[符號位不變](值3) ==> 轉成10進制[注意符號位:1負數;0正數]
        System.out.println(~7); // -8
        /*
        7: 0000 0000 0000 0000 0000 0000 0000 0111
      取反:1111 1111 1111 1111 1111 1111 1111 1000   負數的補碼
    求反碼:1111 1111 1111 1111 1111 1111 1111 0111  補碼減1 ()
再取反得原碼:1000 0000 0000 0000 0000 0000 0000 1000 得原碼
符號位爲1 確定值爲負數;1000 轉爲10進製爲8 ===> -8
         */

        System.out.println(~9); //-10
        /*
原碼、反碼、補碼: 0000 0000 0000 0000 0000 0000 0001 0001
           取反: 1111 1111 1111 1111 1111 1111 1110 1110
    減一獲得補碼: 1111 1111 1111 1111 1111 1111 1110 1101
      取反得原碼: 1000 0000 0000 0000 0000 0000 0001 0010
         */

        System.out.println(~88); //-89
        /*
原碼、反碼、補碼: 0000 0000 0000 0000 0000 0000 0101 1000
           取反: 1111 1111 1111 1111 1111 1111 1010 0111
           減一: 1111 1111 1111 1111 1111 1111 1010 0110
         再取反: 1000 0000 0000 0000 0000 0000 0101 1001
         */
         
        /**
         * 負數二進制的三種表現形式
         * 1.原碼: 絕對值的二進制(符號位爲1)
         * 2.反碼: 原碼取反(符號位不參與運算)
         * 3.補碼: 取反之後 + 1
         */
// 負數步驟 轉成原碼(絕對值原碼符號位爲1) ==> 原碼取反(值1) ==> 值1+1[符號位不變](值2) ==> 再取反[符號位不變](值3) ==> 轉成10進制[注意符號位:1負數;0正數]
        System.out.println(~-9); //8
        /*
      原碼: 1000 0000 0000 0000 0000 0000 0000 1001
      取反: 0111 1111 1111 1111 1111 1111 1111 0110
      加一: 0111 1111 1111 1111 1111 1111 1111 0111
    再取反: 0000 0000 0000 0000 0000 0000 0000 1000
         */

        System.out.println(~-7); //6
        /*
      原碼: 1000 0000 0000 0000 0000 0000 0000 0111
      取反: 0111 1111 1111 1111 1111 1111 1111 1000
      加一: 0111 1111 1111 1111 1111 1111 1111 1001
    再取反: 0000 0000 0000 0000 0000 0000 0000 0110
         */

        System.out.println(~-88); //87
        /*
         原碼: 1000 0000 0000 0000 0000 0000 0101 1000
         取反: 0111 1111 1111 1111 1111 1111 1010 0111
         加一: 0111 1111 1111 1111 1111 1111 1010 1000
       再取反: 0000 0000 0000 0000 0000 0000 0101 0111
         */

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