Java的位運算符與二進制轉換

轉換:html

Java整型數據類型有:byte、char、short、int、long。要把它們轉換成二進制的原碼形式,必須明白他們各佔幾個字節。,一個字節==8位數web

 數據類型                           所佔位數
      byte                                       8 
      boolean                                8
      short                                    16
      int                                         32 
      long                                      64 
      float                                      32 
      double                                  64 
      char                                     16
性能

byte
正數最大位0111 1111,也就是數字127 
負數最大爲1111 1111,也就是數字-128
反碼與補碼
一、反碼:
        一個數若是是正,則它的反碼與原碼相同;
        一個數若是是負,則符號位爲1,其他各位是對原碼取反;

二、補碼:利用溢出,咱們能夠將減法變成加法
       對於十進制數,從9獲得5可用減法:
       9-4=5    由於4+6=10,咱們能夠將6做爲4的補數
       改寫爲加法:
       9+6=15(去掉高位1,也就是減10)獲得5.

       對於十六進制數,從c到5可用減法:
       c-7=5    由於7+9=16 將9做爲7的補數
       改寫爲加法:
       c+9=15(去掉高位1,也就是減16)獲得5.

    在計算機中,若是咱們用1個字節表示一個數,一個字節有8位,超過8位就進1,在內存中狀況爲(100000000),進位1被丟棄。

    ⑴一個數爲正,則它的原碼、反碼、補碼相同
    ⑵一個數爲負,剛符號位爲1,其他各位是對原碼取反,而後整個數加1
     詳細請參考http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html
Integer.toHexString的參數是int,若是不進行&0xff,那麼當一個byte會轉換成int時,因爲int是32位,而byte只有8位這時會進行補位,
例如補碼11111111的十進制數爲-1轉換爲int時變爲11111111111111111111111111111111好多1啊,即0xffffffff可是這個數是不對的,這種補位就會形成偏差。
和0xff相與後,高24比特就會被清0了,結果就對了。
spa

還須要明白一點的是:計算機表示數字正負不是用+ -加減號來表示,而是用最高位數字來表示,0表示正,1表示負orm

在計算機系統中,數值一概用補碼來表示(存儲)。
主要緣由:使用補碼,能夠將符號位和其它位統一處理;同時,減法也可按加法來處理。另外,兩個用補
碼錶示的數相加時,若是最高位(符號位)有進位,則進位被捨棄。
補碼與原碼的轉換過程幾乎是相同的。
數值的補碼錶示也分兩種狀況:
(1)正數的補碼:與原碼相同。
      例如,+9的補碼是00001001。
(2)負數的補碼:符號位(最高位)爲1,其他位爲該數絕對值的原碼按位取反;而後整個數加1。
      例如,-7的補碼:由於是負數,則符號位爲「1」,整個爲10000111;其他7位爲-7的絕對值+7的原碼
     0000111按位取反爲1111000;再加1,因此-7的補碼是11111001。
已知一個數的補碼,求原碼的操做分兩種狀況:
(1)若是補碼的符號位爲「0」,表示是一個正數,因此補碼就是該數的原碼。
(2)若是補碼的符號位爲「1」,表示是一個負數,求原碼的操做能夠是:符號位爲1,其他各位取反,而後再整個數加1。
     例如,已知一個補碼爲11111001,則原碼是10000111(-7):由於符號位爲「1」,表示是一個負數,因此該位不變,仍爲「1」;其他7位1111001取反後爲0000110;再加1,因此是10000111。htm

源碼:是什麼就是什麼。負數就是最前面符號位爲1。
反碼:正的就是補碼,負的就是各位取反,0換1,1換0,注意,最高位符號爲不變。
補碼:正的就是源碼,負的就是反碼+1
好比: -1 -2
以8位二進制爲例
源碼:10000001 10000010
反碼:11111110 11111101
補碼:11111111 11111110
補碼這樣作的好處是什麼呢?
請看-1+(-2)電腦怎麼作:
用源碼:10000001 + (10000010)=00000011 這是什麼?是-3嗎?不是,是3。因此不能直接用源碼作加法。
用反碼:11111110 + (11111101)=11111011 這是什麼?是反碼的"-4"
用補碼:11111111 + (11111110)=11111101 末尾減一再取反得10000011,因此結果是補碼的-3。
反碼爲何出錯?以4位數爲例,高位爲符號位(括號內爲絕對值):
1010 (2)取反 1101 (5)
1011 (3)取反 1100 (4)
而後 -2 + (-3) 變成了 -(5 + 4)超出8的部分捨去,得 1001,再取反得 1110,成了-6
究其緣由:各位取反的兩數相加:1010+0101=1111必是全1即絕對值爲7,2->5,3->4,相對於8共誤差了2,而後9=1mod8,1->6,只修正了1點誤差,
結果就出現了1的誤差。補碼中末尾加一就是修正了該誤差,獲得正確的結果。即2->6,3->5.相對於8無誤差11=3mod8,3->5。blog

位運算符:內存

位移進制運算

帶符號右移 題:-15 >> 2 = -4

15原碼:   00000000 00000000 00000000 00001111 //32位,二進制
反碼:    11111111 11111111 11111111 11110000 //0變1,1變0
補碼:    11111111 11111111 11111111 11110001 //最後位加1,-15二進制
右移2位:  11111111 11111111 11111111 11111100 //右邊丟棄2位,前面30位保留,左邊補1
取反:      00000000 00000000 00000000 00000011 //0變1,1變0
+1:                                       3+1
結果:                                     =-4 //負號保留,十進制

帶符號左移 題: 10 << 2 = 40
10 補碼:    00000000 00000000 00000000 00001010 //32位,二進制
左移2位:    00000000 00000000 00000000 00101000 //左邊丟棄2位,右邊補0
結果:                                        40 //十進制
 

無符號右移 題:-4321 >>> 30 = 3
4321原碼:         00000000 00000000 00010000 11100011 //32位,二進制
反碼:           11111111 11111111 11101111 00011100 //0變1,1變0
補碼:           11111111 11111111 11101111 00011101 //最後位加1,-4321二進制
無符號右移30位:  00000000 00000000 00000000 00000011 //右邊丟棄30位,前面二位保留,左邊補0
結果:                                                3 //十進制ci


& 位邏輯與 題:44 & 21 = 4
44 補碼:    00000000 00000000 00000000 00101100 //32位,二進制
21 補碼:    00000000 00000000 00000000 00010101 //32位,二進制
& 運算:     00000000 00000000 00000000 00000100 //對應的兩個二進制位均爲1時 結果位才爲1 不然爲0
結果:                                         4 //十進制   
                               
| 位邏輯與 題:9 | 5 = 13
9 補碼:    00000000 00000000 00000000 00001001 //32位,二進制
5 補碼:    00000000 00000000 00000000 00000101 //32位,二進制
| 運算:    00000000 00000000 00000000 00001101 //對應的二個二進制位有一個爲1時,結果位就爲1
結果:                                       13 //十進制

^ 位邏輯異或 題: 9 ^ 5 = 12
9 補碼:    00000000 00000000 00000000 00001001 //32位,二進制
5 補碼:    00000000 00000000 00000000 00000101 //32位,二進制
| 運算:    00000000 00000000 00000000 00001100 //對應的二進制位相異時,結果爲1
結果:                                       12 //十進制

~ 位邏輯反 題: ~9 = -10
9 補碼:    00000000 00000000 00000000 00001001 //32位,二進制
~ 運算:    11111111 11111111 11111111 11110110 //最高位爲1表示爲一個負數,則進行取反加1
取反:      00000000 00000000 00000000 00001001 //32位,二進制
+1:                                      9+1 //32位,二進制
結果:                                      -10 //十進制源碼

因爲數據類型所佔字節是有限的,而位移的大小卻能夠任意大小,因此可能存在位移後超過了該數據類型的表示範圍,因而有了這樣的規定: 若是爲int數據類型,且位移位數大於32位,則首先把位移位數對32取模,否則位移超過總位數沒意義的。因此4>>32與4>>0是等價的。

若是爲long類型,且位移位數大於64位,則首先把位移位數對64取模,若沒超過64位則不用對位數取模。

若是爲byte、char、short,則會首先將他們擴充到32位,而後的規則就按照int類型來處理。

 

實際應用:


1.  判斷int型變量a是奇數仍是偶數    
     a&1  = 0 偶數 
     a&1 =  1 奇數 
2.  求平均值,好比有兩個int類型變量x、y,首先要求x+y的和,再除以2,可是有可能x+y的結果會超過int的最大表示範圍,因此位運算就派上用場啦。
      (x&y)+((x^y)>>1); 
3.  對於一個大於0的整數,判斷它是否是2的幾回方
    ((x&(x-1))==0)&&(x!=0); 
4.  好比有兩個int類型變量x、y,要求二者數字交換,位運算的實現方法:性能絕對高效
    x ^= y; 
    y ^= x; 
    x ^= y; 
5. 求絕對值
    int abs( int x ) 
   { 
     int y ; 
     y = x >> 31 ; 
    return (x^y)-y ;        //or: (x+y)^y     } 6.  取模運算,採用位運算實現:     a % (2^n) 等價於 a & (2^n - 1)  7.  乘法運算   採用位運算實現     a * (2^n) 等價於 a << n 8.   除法運算轉化成位運算      a / (2^n) 等價於 a>> n  9.   求相反數      (~x+1)  10  a % 2 等價於 a & 1 

相關文章
相關標籤/搜索