整數的二進制、位運算、邏輯與或


二進制 

  正整數的二進制表示 (假定類型是byte)

   正整數的二進制表示與此類似, 只是在十進制中,每個位置可以有10個數字,從0到9,但在二進制中,每個位置只能是0或1。

    例如: 0000 1010     ==>   10  

     負整數的二進制表示 (假定類型是byte)

  十進制的負數表示就是在前面加一個負數符號 -,例如-123。但二進制如何表示負數呢? 

  其實概念是類似的,二進制使用最高位表示符號位,用1表示負數,用0表示正數。

  但負數表示不是簡單的將最高位變為1,比如說:

    •   byte a = -1,如果只是將最高位變為1,二進制應該是10000001,但實際上,它應該是11111111。

    •   byte a=-127,如果只是將最高位變為1,二進制應該是11111111,但實際上,它卻應該是10000001。

 

  和我們的直覺正好相反,這是什么表示法?這種表示法稱為補碼表示法,而符合我們直覺的表示稱為原碼表示法,補碼表示就是在原碼表示的基礎上取反然后加1。取反就是將0變為1,1變為0。

  負數的二進制表示就是對應的正數的補碼表示,比如說:

    •   -1:1的原碼表示是00000001,取反是11111110,然后再加1,就是11111111。

    •   -2:2的原碼表示是00000010,取反是11111101,然后再加1,就是11111110

    •   -127:127的原碼表示是01111111,取反是10000000,然后再加1,就是10000001。

       給定一個負數二進制表示,要想知道它的十進制值,可以采用相同的補碼運算。比如:10010010,首先取反,變為01101101,然后加1,結果為01101110,它的十進制值為110,所以原值就是-110。

       byte類型,正數最大表示是01111111,即127,負數最大表示是10000000,即-128,表示范圍就是 -128到127。其他類型的整數也類似,負數能多表示一個數。

 

負整數為什么采用補碼呢?

  負整數為什么要采用這種奇怪的表示形式呢?原因是:只有這種形式,計算機才能實現正確的加減法。

  計算機其實只能做加法,1-1其實是1+(-1)。如果用原碼表示,計算結果是不對的。比如說:

      

1   -> 00000001

-1 -> 10000001

+ ------------------

-2 -> 10000010

 

用符合直覺的原碼表示,1-1的結果是-2。

 

如果是補碼表示:

 

1   -> 00000001

-1 -> 11111111

+ ------------------

0  ->  00000000

 

結果是正確的。

 

再比如,5-3:

 

5   -> 00000101

-3 -> 11111101

+ ------------------

2  ->  00000010

 

結果也是正確的。

 

就是這樣的,看上去可能比較奇怪和難以理解,但這種表示其實是非常嚴謹和正確的。

 

理解了二進制加減法,我們就能理解為什么正數的運算結果可能出現負數了。當計算結果超出表示范圍的時候,最高位往往是1,然后就會被看做負數。比如說,127+1:

 

127   -> 01111111

1       -> 00000001

+ ------------------

-128  ->10000000

 

計算結果超出了byte的表示范圍,會被看做-128。

補碼的好處

  以 +1 和 -1 作加法運算為例,如下圖所示:

  

  相信你已經發現,1 + (-1) 這樣的加法運算只要將二進制數相加,然后-1的末位就會變成2,根據逢2進1機制,從右至左依次所有位都會變成0。

  最后,最左端的符號位也會進位1變成0,丟棄溢出的1,就得到最后的結果0的二進制表示32個0。

  對照本節開頭的圖,會發現所有的減法都可以轉換成二進制位的加法運算:1-2 可以轉換成1+(-2),(-1)-(-2)可以轉換成-1+2……

  這跟數學中的表示是一樣的,而且非常地方便計算(很多計算機科學家都是從數學領域轉入計算機工程,所以在很多細微之處的都能見到數學的影子)。因此,現代計算機硬件結構實際上只設計了加法器,大部分的減法其實都是轉換成加法后再運算。

   備注:

    以正數的二進制數表示為基准,負數的表示只改變符號位,這樣的表示方式就是原碼。因此,正數的表示方式都是原碼。

    反碼就是將原碼除符號位以外的值全部取反,原來是1的變為0,原來是0的變為1。

    補碼就是在反碼的基礎上,在二進制數的右端末位加1(逢2進1)。

小結

    正數的原碼和反碼和補碼都一致;負數的原碼是正數的符號位取反;負數的反碼是原碼的非符號位取反;負數的補碼是反碼加1。

 

位運算

  • 左移:操作符為<<,向左移動,右邊的低位補0,高位的就舍棄掉了,將二進制看做整數,左移1位就相當於乘以2。

  • 無符號右移:操作符為>>>,向右移動,右邊的舍棄掉,左邊補0。

  • 有符號右移:操作符為>>,向右移動,右邊的舍棄掉,左邊補什么取決於原來最高位是什么,原來是1就補1,原來是0就補0,將二進制看做整數,右移1位相當於除以2。

邏輯與或

  兩種邏輯與(&&和&)的運算規則基本相同,兩種邏輯或(|| 和 |)的運算規則也基本相同。 &和|運算是把邏輯表達式全部計算完,而&&和||運算具有短路計算功能。

  所謂短路計算,是指系統從左至右進行邏輯表達式的計算,一旦出現計算結果已經確定的情況,則計算過程即被終止。 對於&&運算來說,只要運算符左端的值為false,則因無論運算符右端的值為true或為false,其最終結果都為false。 所以,系統一旦判斷出&&運算符左端的值為false,則系統將終止其后的計算過程; 對於 || 運算來說,只要運算符左端的值為true,則因無論運算符右端的值為true或為false,其最終結果都為true。 所以,系統一旦判斷出|| 運算符左端的值為true,則系統將終止其后的計算過程。

小技巧

  ⑴ 乘法除法:n * 2 等價於 n << 1; n * 5 等價於 n << 2 + 1; n / 2 等價於 n >> 1。

  備注:JVM執行時會自動轉化,大部分其它高級語言的編譯器會做類似優化轉換,所以除非有特殊的理由,否則別這么寫。

  ⑵ 取低位:n & 0x0000FFFF;取高位:n & 0xFFFF0000。

  ⑶ 奇偶判斷:n & 1,等於0為偶,等於1為奇。

  ⑷ 正負判斷:(n >>> 31) & 1,等於0為正,等於1為負。

  ⑸ 取余:n % m ,如m為2的冪次方,可用(n & (m - 1))替代。

 

 

參考:老馬說編程

  

Java位運算符及二進制常識


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM