Java基礎系列-二進位制操作

唯一浩哥發表於2019-02-22

原創文章,轉載請標註出處:《Java基礎系列-二進位制操作》

概述

Java原始碼中涉及到大量的二進位制操作,非常的複雜,但非常的快速。

Java二進位制表示法

首先了解下二進位制,二進位制是相對十進位制而言的,當然還有八進位制,十六進位制等等,我們常用的都是十進位制,計算機用的都是二進位制,而符號表示常用十六進位制。

二進位制就是隻有0、1兩個值表示的數,規則是逢二進一。

整數表示法

Java中使用補碼來表示負數,具體就是除符號位之外,剩餘位取反加1,符號位不變還是1(符號位0-正數,1-負數)

Java中二進位制符號位也不是固定的,在Byte型別的數值中,由於其為一個位元組即八位取值範圍為-128到127,其符號位就是第8位二進位制位。
如下所示:

Byte型資料
1 -> 0000 0001
-1 -> 1111 1111(計算:1為00000001,-1為10000001,取反為11111110,加1為11111111)
127 -> 0111 1111
-127 -> 1000 0001(計算:127為01111111,-127為11111111,取反為10000000,加1為10000001)
-128 -> 1000 0000(計算:128為100000000,取8位為00000000,-128為10000000,取反為11111111,加1為10000000)

Short型數為兩個位元組16位數值,其符號位為第16位:

Short型資料
1 -> 0000 0000 0000 0001
-1 -> 1111 1111 1111 1111(計算:1為0000000000000001,-1為1000000000000001,取反為1111111111111110,加1為1111111111111111)
32767 -> 0111 1111 1111 1111
-32767 -> 1000 0000 0000 0001(計算:32767為0111111111111111,-32767為1111111111111111,取反為1000000000000000,加1為1000000000000001)
-32768 -> 1000 0000 0000 0000(計算:32768為10000000000000000,取16位為0000000000000000,-32768為1000000000000000,取反為1111111111111111,加1為1000000000000000)

Integer為32位,Long為64位,表示方式如上,Integer第32位為符號位,Long型第64位為符號位。

浮點數表示法

Java中的浮點數大多數都無法精確表示,為什麼呢?因為使用二進位制來表示小數一樣存在和十進位制表示小數一樣的問題,存在無限迴圈的小數和無限不迴圈的小數,比如十進位制的1/3,十進位制為0.333…無限個3,二進位制表示同樣會有這個問題,二進位制表示0.1、0.2、0.3、0.4等都不能精確表示,0.5可以表示為2^(-1),可以精確表示,可見只有可以精確的使用科學計數法表示的二進位制小數才能精確表示,其他的一律無法精確表示。

Java中使用32位的float和64位的double表示浮點小數。

Float型浮點數
格式:1位符號位,8位指數,23位尾數(S1_E8_M23)
符號位:0-正數,1-負數
指數位:採用移位儲存,即用真實數值+127的二進位制值來表示,比如,1要表示成128(即:10000000),128表示為255(即11111111)
尾數位:將十進位制數轉化為二進位制之後,轉化為科學計數法形式,取小數位作為尾數位,不足23位結尾補0
0.5 -> 0011 1111 0000 0000 0000 0000 0000 0000
(計算:0.5 = 1/2,即2^(-1),指數位為-1+127=126,即01111110,尾數為0,因為是正數,符號位為0)
10.5 -> 0100 0001 0010 1000 0000 0000 0000 0000 
(計算:10的二進位制為1010,0.5的二進位制為0.1,所以10.5的二進位制Wie1010.1,科學計數法表示為1.0101E11,如此一來,指數位為3+127=130,即10000010,符號位為0,尾數為0101,後面補0,夠23位)
35.3 -> 0100 0010 0000 1101 0011 0011 0011 0011
(計算:35的二進位制為100011,0.3的為二進位制為0.01001100110011001100110011001100110011...,合起來就是100011.0100110011001100110011...,科學計數法為1.00011010011001100110011...E101,如此一來,符號位為0,指數位為5+127=132,即10000100,尾數為00011010011001100110011)
Double型浮點數
格式:1位符號位,11位指數,52位尾數
符號位:0-正數,1-負數
指數位:採用移位儲存,用真是數值+1023的二進位制值來表示,比如1要表示成1024(即:10000000000)
尾數位:將十進位制轉化為二進位制,再轉為科學計數法,取小數位作為尾數,不足52位結尾補0
35.3 -> 0100 0000 0100 0001 1010 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110
(計算:35的二進位制為100011,0.3的為二進位制為0.01001100110011001100110011001100110011...,合起來就是100011.0100110011001100110011...,科學計數法為1.00011010011001100110011...E101,如此一來,符號位為0,指數位為5+1023=1028,即10000000100,尾數為0001101001100110011001100110011001100110011001100110)

進位制轉化:

十進位制轉二進位制,整數部分除以2,整除為0,否則為1,直到結果為1,然後從後竄到前的結果就是其二進位制值

比如:10
10/2 = 5  整除      0
5/2 = 2  未整除     1
2/2 = 1  整除       0
1     結果為1,結束  1
最後10的二進位制值為:1010
再比如77
77/2=38    未整除   1
38/2=19       整除    0
19/2=9     未整除   1
9/2=4      未整除   1
4/2=2      整除     0
2/2=1      整除     0
1    結果為1,結束   1
最後77的二進位制為1001101

小數部分的二進位制化,取小數部分乘以2,結果大於等於1,取1,否則取0,再取小數部分乘以2,取值,直到結果為0或者迴圈

比如:10.22
先進行整數部分二進位制,結果為1010
再進行小數部分二進位制:
0.22 * 2 = 0.44   0
0.44 * 2 = 0.88   0
0.88 * 2 = 1.76   1
0.76 * 2 = 1.52   1
0.52 * 2 = 1.04   1
0.04 * 2 = 0.08   0
0.08 * 2 = 0.16   0
0.16 * 2 = 0.32   0
0.32 * 2 = 0.64   0
0.64 * 2 = 1.28   1
0.28 * 2 = 0.56   0
0.56 * 2 = 1.12   1
0.12 * 2 = 0.24   0
0.24 * 2 = 0.48   0
0.48 * 2 = 0.96   0
0.96 * 2 = 1.92   1
0.92 * 2 = 1.84   1
0.84 * 2 = 1.68   1
0.68 * 2 = 1.36   1
0.36 * 2 = 0.72   0
0.72 * 2 = 1.44   1
...
結果就是1010.00111000010100011110...
若是以科學計數法表示那就是1.01000111000010100011110...E11
若是表示成float的二進位制形式那就是:0100 0001 0010 0011 1000 0101 0001 1110

Java二進位制運算子

與:&

與操作規則:全1為1,否則為0
例如:
    1010 & 0101 = 0000
    1111 & 0000 = 0000
    1010 & 1111 = 1010
    0101 & 0000 = 0000

擴充套件:二進位制中的1的與操作具有保留原值的效果,任何值(0,1)和1進行與操作結果都不會變。這一點在HashMap中得以使用。

或:|

或操作規則:有1為1,全0為0
例如:
    1010 | 0101 = 1111
    1111 | 0000 = 1111
    1010 | 1111 = 1111
    0101 | 0000 = 0101

擴充套件:二進位制中的0的或操作也具有保留原值的效果,任何值(0,1)和0進行或操作結果都不會變。

非:~

非操作規則:0為1,1為0
例如:
    ~1111 = 0000

異或:^

異或操作規則:相同為0,不同為1
例如:
    1010 ^ 0101 = 1111
    1111 ^ 0000 = 1111
    1010 ^ 1111 = 0101
    0101 ^ 0000 = 0101

擴充套件:二進位制中的0的異或操作具有保留原值的效果,1的異或操作具有取反的效果。

左移:<<

左移規則:符號位保持不變的情況下剩餘全部左移一位,低位補0,相當於乘以2的結果
例如:
    0011 << 2 = 1100
    1000 0000 1000 0001 << 2 = 1000 0010 0000 0100  (首位1為符號位)

右移:>>

右移規則:符號位保持不變的情況下剩餘全部右移一位,高位補0,相當於除以2的結果
例如:
    0011 >> 2 = 0000
    1000 0000 1000 0001 >> 2 = 1000 0000 0010 0000 (首位1為符號位)

無符號右移:>>>

無符號右移規則:全員右移一位,高位補0,相當於除以2的結果
例如:
    1000 0000 1000 0001 >> 2 = 0010 0000 0010 0000 (首位1為符號位)

二進位制操作

參考例子中的操作:

public class BinaryTest {
    public static void main(String[] args){
        int a = 100;
        String as = Integer.toBinaryString(a);// 整數的二進位制表示,可輸出二進位制字串
        long b = 200;
        String bs = Long.toBinaryString(b);// 長整數的二進位制表示,可輸出二進位制字串
        float c = 30.0f;
        int ci = Float.floatToIntBits(c);// 將浮點數的二進位制佈局解析為整型表示
        int ci2 = Float.floatToRawIntBits(c);// 將浮點數的二進位制佈局解析為整型表示
        float f2 = Float.intBitsToFloat(a);// 將整型數的佈局解析為一個浮點數
        double d = 302.22d;
        Long dl = Double.doubleToLongBits(d);// 將浮點數的二進位制佈局解析為長整型表示
        Long dl2 = Double.doubleToRawLongBits(d);// 將浮點數的二進位制佈局解析為長整型表示
        double d2 = Double.longBitsToDouble(b);// 將長整型數的佈局解析為一個雙精度浮點數
    }
}

相關文章