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