二進制你了解多少?


2進制

2進制

什么是2進制

逢2進1的計數規則

案例:

public class Demo01 {
    public static void main(String[] args) {
        /*
         * 2進制
         * - Java 先編譯后運行
         * - Java 再編譯期間,將10進制字面量編譯為2進制
         * - Java 輸出時候將2進制轉換為10進制輸出
         * - Java API Integer.toBinaryString() 
         *   可以輸出2進制內容
         * - toBinaryString()輸出時候自動省略了高位0
         */
        int i = 50; //編譯后 110010 運行時候 110010
        System.out.println(i); 
        //輸出時候110010 轉換為 "50" 再輸出
        System.out.println(Integer.toBinaryString(i)); 
        //110010
        //輸出0~200的2進制,研究其值
        for(int n = 0; n<=200; n++){
            System.out.println(Integer.toBinaryString(n));
        }
    }
}

0~200的2進制

如何將2進制正數轉換為10進制: 將每個1位的權值進行累加

00000000 00000000 00000000 00000000 = 0
00000000 00000000 00000000 00000001 = 1
00000000 00000000 00000000 00000010 = 2
00000000 00000000 00000000 00000011 = 2+1 = 3
00000000 00000000 00000000 00000100 = 4
00000000 00000000 00000000 00000101 = 4+1=5
00000000 00000000 00000000 00000110 = 4+2=6
00000000 00000000 00000000 00000111 = 4+2+1=7
00000000 00000000 00000000 00001000 = 8
00000000 00000000 00000000 00001001 = 8+1 = 9
00000000 00000000 00000000 00001010 = 8+2 = 10
... ...
00000000 00000000 00000000 00100101 = 32+4+1=37
... ...
00000000 00000000 00000000 00101011 = ?

自己動手練習練習: 輸出0~200之間的2進制, 隨機抽取20個數, 手工計算10進制值,自己編程驗證.!

16進制

逢16進1的計數規則

16進制用於縮寫2進制, 用於簡化2進制!

  • 2進制書寫非常繁瑣, 容易錯誤
  • 利用16進制, 從2進制最低位開始, 每4位縮寫為一個16進制數. 縮寫后使用方便!
public class Demo02 {
    public static void main(String[] args) {
        /*
         * 2進制書寫繁瑣
         * - Java 7 開始提供了2進制直接量前綴 0b
         * - 在數字中使用下划線分割不影響數值
         * - 利用16進制縮寫,可以簡化2進制
         *   從最低位開始, 每4位縮寫為一位16進制
         */
        int n = 100; //1~9開頭的數字是10進制直接量
        int m = 0b100; //0b開頭, 則表示是2進制
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toBinaryString(m));
        n = 0b100_11111100_01110001_01011111;
        //    4   f   c    7   1    5   f
        m = 0x4fc715f;
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toBinaryString(m));
        //任意編寫5組32位2進制數, 利用16進制縮寫, 自己輸出驗證
    }
}

8進制

利用8進制可以對2進制進行3位3位縮寫,

從2進制最低位開始, 每3位縮寫為一位8進制.

  • 縮寫不算方便, 沒有16進制縮寫的短
  • 8進制數字 0~7
  • Java中8進制前綴是 0, 這個經常在考試中出現

如:

int n = 080;
System.out.println(n);

上述代碼輸出結果 ( D ): A.080 B.80 C.100 D.編譯錯誤

補碼(數字編碼規則)

什么是補碼

補碼是計算機中用於處理有符號(正數和負數)數的一種底層編碼規則.

  • 補碼編碼思路: 將固定位數的2進制數, 分一半作為負數使用.
  • 補碼計算時候會自動溢出: 超過固定位數的數字自動舍棄.

利用4位2進制數討論補碼編碼原理, 然后推廣到32位int類型.

分析: 如何設計 4 位補碼

案例:

public class Demo03 {
    public static void main(String[] args) {
        /*
         * 補碼的編碼規律
         * Binary: 2進制
         * Integer: 整數
         */
        int n = -3;
        System.out.println(Integer.toBinaryString(n));
        //max 最大  value 值
        int max = Integer.MAX_VALUE;
        int min = Integer.MIN_VALUE;
        System.out.println(max); //  2147483647
        System.out.println(min); // -2147483648
        System.out.println(Integer.toBinaryString(max));
        System.out.println(Integer.toBinaryString(min));

        n = -1;
        System.out.println(Integer.toBinaryString(n));

        long lmax = Long.MAX_VALUE;
        long lmin = Long.MIN_VALUE;
        long l = -1L;
        System.out.println(Long.toBinaryString(lmax));
        System.out.println(Long.toBinaryString(lmin));
        System.out.println(Long.toBinaryString(l));
        
    }
}

負數的編碼規律

  • 首先記住-1的編碼
  • 研究一個負數(最高位是1),檢查這個數比-1少多少
                            8421
11111111111111111111111111111111 =-1
11111111111111111111111111111101 =-1-2=-3
11111111111111111111111111111001 =-1-2-4=-7
11111111111111111111111111100110 =-1-1-8-16=-26

輸出-200到0的編碼,隨機挑選20個數字, 手工計算負數值, 自己演算結果。

/*
 * 研究負數的編碼
 */
for(int i=-200; i<0; i++){
    System.out.println(Integer.toBinaryString(i));
}

補碼的互補對稱現象

補碼編碼結果有一個巧合,正負數互補對稱, 因為互補對稱, 稱作補碼。

互補對稱公式: -n = ~n + 1, 最小值除外

面試題目1:

System.out.println(~100+1);

上述代碼輸出結果是( C )

A. -98 B.-99 C.-100 D.-101

面試題目2:

System.out.println(~100);

上述代碼輸出結果是( D )

A. -98 B.-99 C.-100 D.-101

面試題目3:

System.out.println(~-100);

上述代碼輸出結果是( B )

A.98 B.99 C.100 D.101

2進制運算

運算符號:

~ 取反
& 與運算
| 或運算
>>> 右移位
>> 數學右移位
<< 左移位

& 與計算

基本運算規則,邏輯乘法:有0則0

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

運算時候, 將兩個整數對齊位數, 對應的位進行與運算:

舉個例子:

           7   7    8   3    6   5    a   b 
n =       01110111 10000011 01100101 10101011
m =       00000000 00000000 00000000 11111111 
k = n&m   00000000 00000000 00000000 10101011

如上案例的意義:k中存儲的是數字n的最后8位數。 m是一個用於切分n的一個“掩碼(Mask)”,按照1的個數稱為 x 位掩碼。

程序:

int n = 0x778365ab;
int m = 0xff;
int k = n & m;
//按照2進制輸出 n m k 

>>> 右移位運算

運算規則: 將2進制數位整體向右移動,地位自動溢出,高位補0

舉個例子:

n =        01111110 00010111 01111100 01110111
m = n>>>1  001111110 00010111 01111100 0111011
k = n>>>2  0001111110 00010111 01111100 011101
g = n>>>8  00000000 01111110 00010111 01111100
b3= (n>>>8) & 0xff;

程序:

int n = 0x7e177c77;
int m = n>>>1;
int k = n>>>2;
int g = n>>>8;
int b1 = (n>>>24) & 0xff;
int b2 = (n>>>16) & 0xff;
int b3 = (n>>>8) & 0xff;
int b4 = n & 0xff;
//按照2進制輸出  n m k g b3

| 或運算

運算規則,邏輯加法, 有1則1:

0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

運算時候將兩個2進制數對齊位,對應的位進行或運算:

n   =    00000000 00000000 00000000 10111011
m   =    00000000 00000000 11110111 00000000
k = n|m  00000000 00000000 11110111 10111011 

上述案例的意義:錯位合並兩個8位數!

案例:

int n = 0xbb;
int m = 0xf700;
int k = n|m;
//檢查 n m k 

<< 左移位運算

規則: 將2進制數整體向左移位,移動以后高位溢出, 低位補0

例子:

n  =      01011101 11111110 00001010 10111010
m = n<<1  1011101 11111110 00001010 101110100
k = n<<2  011101 11111110 00001010 1011101000

案例:

int n = 0x5dfe0aba;
int m = n<<1;
int k = n<<2;

移位運算是數學意義

2進制時候,數字整體向左移動一次, 數值擴大2倍。

案例:

int n = 5;
System.out.println(n<<1); //10
System.out.println(n<<2); //20
System.out.println(n<<3); //40

右移位的區別

>>> 邏輯右移位運算, 無論正負,低位自動溢出,高位補0, 僅僅在邏輯上將數字向右移動, 不關心是否是數學除以2的結果。

>> 數學右移位運算,移位時候低位自動溢出, 正數時候高位補0, 負數時候高位補1,結果是數學除以2,向小反向取整數的結果

舉個例子,負數時候:

n  =    11111111 11111111 11111111 11001110 =-1-1-16-32=-50
m=n>>1  111111111 11111111 11111111 1100111 =-1-8-16=-25
k=n>>2  1111111111 11111111 11111111 110011 =-1-4-8=-13
g=n>>>1 011111111 11111111 11111111 1100111 =?

用法:

  • 如果用於替代 數學除以2 時候使用 >>
  • 如果用於將2進制數整體向右移位,不關心數學結果,使用 >>>

經典面試題目:

  • 將n * 8 可以替換(優化)為 ( n<<3 )
  • 將n / 2 可以替換(優化)為 ( n>>1 )

拆分合並整數

為何需要對整數進行拆分合並:

  • 互聯網按照字節(8位)為單位傳輸數據
  • 任何數據都需要拆分為 字節(8位) 數據進行傳輸: 編碼
    • 整數:32位需要拆分為 4字節
    • long:64位需要拆分為 8字節
    • ... ...
  • 收到數據時候, 再將字節組合為數據:解碼

整數的拆分(編碼):

             b1       b2       b3       b4 
n    =    01111011 11110000 11011100 00111101
b1   =    00000000 00000000 00000000 01111011
b2   =    00000000 00000000 00000000 11110000
b3   =    00000000 00000000 00000000 11011100
b4   =    00000000 00000000 00000000 00111101

int b1 = (n>>>24) & 0xff;
int b2 = (n>>>16) & 0xff;
int b3 = (n>>>8) & 0xff;
int b4 = n & 0xff;

整數的解碼(合並):自己編寫代碼進行測試

b1   =    00000000 00000000 00000000 01111011
b2   =    00000000 00000000 00000000 11110000
b3   =    00000000 00000000 00000000 11011100
b4   =    00000000 00000000 00000000 00111101
n    =    01111011 11110000 11011100 00111101

b1<<24    01111011 00000000 00000000 00000000 
b2<<16    00000000 11110000 00000000 00000000 
b3<<8     00000000 00000000 11011100 00000000
b4<<0     00000000 00000000 00000000 00111101

n = (b1<<24) | (b2<<16) | (b3<<8) | (b4<<0) 

作業:該你自己動手啦

將一個 long 類型整數拆分為 8個字節。

將8個 字節合並為一個long 類型整數。

檢查long類型的最大值,最小值和-1,-3


免責聲明!

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



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