二進位制(十六進位制)的總結:
二進位制表示有點難度,所以我專門對這一知識點進行總結,全當做是複習吧! 首先:什麼是二進位制? 二進位制和十進位制一樣,是一種計數的規則,十進位制是逢十進一 那麼顧名思義,二進位制就是逢二進一了,依次類推,N進位制就是逢N進一就是了,不過我們用的多的也就是: 二進位制,十進位制,十六進位制
##為什麼要用二進位制;因為二進位制只有0和1,而計算機是由邏輯電路組成,邏輯電路就兩個狀態,通電和不通電,所以正好用 0和1來表示兩種狀態,所以使用二進位制是計算機硬體成本最優的選擇! 而且二進位制也正好符合計數的規則,而只要是能計數,都可以實現任何數學運算
##二進位制主要有哪些應用呢:補碼,16進位制,文字編碼
科普!!:: 這裡稍微說一下:其實我們在電腦上看到的那些數都不是二進位制,而是我們知道的十進位制,可電腦並不認識十進位制,而且電腦都是底層都是通過 二進位制來進行資料處理的(不管什麼資料),所以計算機並不認識十進位制,更準確的來說計算機連二進位制也不認識,因為計算機只是認識通電和不通電, 也就是電路的開和關.換句話說也就是電流的高低起伏的變化. 那麼計算機又是如何處理二進位制的呢,其實很簡單,二進位制只是認為的規定,讓計算機電路通了記做"1",斷了記做"0",所以這樣計算機永遠就只有兩種 狀態,而不需要考慮說還需要其他狀態,生產成本降低了. 在我們學習的java裡面,輸出的都是十進位制,其實在只是我們看到的是十進位制,內部可並不是這樣子的,java一直都是在用二進位制進行計算,只不過我們 看不到而已.那麼這個魔術手段是什麼呢:首先當我們把資料輸進電腦,java會自動呼叫 parseInt() 方法,來把我們輸入的十進位制資料轉換成二進位制, 然後用這些二進位制資料進行著數學計算,最後要輸出結果的時候,java又會呼叫| toString() |方法來把二進位制資料轉換成十進位制,這一系列轉換我們可以debug跟蹤到.
先來說一下二進位制的技術規則吧: 首先二進位制只用兩個數來計數:1 | 0 也就是隻要有一位上等於2了就要向前進一,和十進位制一樣,簡單來說就是"逢二進一"
十進位制也好,二進位制也好,都有權這一說法,權表示的是在本位置上的數字是多少就是代表這個數字乘以權,舉個栗子: 拿我們最熟悉十進位制來說,個位上的5就是代表51=5,十位上的5就是代表510=50,百位上的5就是代表5*100=500,依次類推; 即:…|1000|100|10|1------這裡的規律是…|103|102|101|100 所以從十進位制上有規律了,那麼二進位制就好找規律了,十進位制的權是10n,那麼二進位制每一位的權就是2n了 即二進位制的權就是…|256|128|64|32|16|8|4|2|1
下面來總結一下二進位制的轉換把!
##十進位制轉二進位制:(其實這個很簡單) 第一步找到十進位制數在二進位制的權的區間,例如十進位制的134在二進位制的256和128之間 第二步用134依次減二進位制的權,如果減完大於或等於零,則說明能減,就在二進位制的權下面標一個1,然後繼續 用餘數去依次往下減,和上面的一樣,小於權的在權下面標0,一直減到權的最後一位,二進位制這就是權下面的0,1組合 例如:134的二進位制就是10000110.
134 256 128 64 32 16 8 4 2 1 1 0 0 0 0 1 1 0 134 6 6 6 6 6 2 0 0
##二進位制轉十進位制: 二進位制轉十進位制其實和十進位制轉二進位制差不多,就是分別在二進位制的每一位下面把權標上,然後用每一位的數乘以權 最後把所有的乘積進行加法運算;
1 0 0 0 0 1 1 0 128 64 32 16 8 4 2 1 得到:2+4+128=134
好了到這裡就學會了二進位制和十進位制的相互轉化; 接下來回顧一下補碼的知識: java在toString 和 parseInt 中封裝了補碼的演算法,在資料輸入和輸出的時候自動呼叫,自動化支援補碼
因為計算機中是不認識負數的, java也是一樣為什麼我們能看到輸出負數呢,那是因為負號都是java經過補碼計算 然後作為一個字元新增上去的. 補碼簡單的理解來說就是計算機利用整數來表示負數,到頭來還是節省了硬體成本. 補碼的規律:
[0]
0000
[-1] 1111 0001 [1]
[-2] 1110 0010 [2]
[-3] 1101 0011 [3]
[-4] 1100 0100 [4]
[-5] 1011 0101 [5]
[-6] 1010 0110 [6]
[-7] 1001 0111 [7](max)
1000
[-8](min)
{上圖就為4位補碼繪圖一}
所以從上圖就能看出來,4位補碼中最大值為0111(7),最小值為1000(-8),-1為:1111 也可以看出來,正數都是以0開頭的,負數都是以1開頭的
補碼就相當於一個時鐘的圓盤,為了更形象的說明,用四位二進位制來說明: 正數 ## 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111
負數 ## 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111
所以這裡第一行代表的是正數:0,1,2,3,4,5,6,7 第二行代表的負數:-8 -7 -6 -5 -4 -3 -2 -1 觀察上面的規律就能發現:正數的最小值是0000,最大值是0111 負數的最小值是1000,最大值是1111 -1的二進位制是1111 所以這4位的最大值是0111,最小值是1000; 上面的栗子是4位2進位制,一個位元組代表8位,一個int型別佔2個位元組,即16位; 所以用int的舉例子的話,int的最大值為:01111111 11111111 11111111 11111111 最小值為:10000000 00000000 00000000 00000000 -1為:11111111 11111111 11111111 11111111
補碼的一些規律: 1##取反對稱規律(這是不符合數學計數規則的,只適用於二進位制)(不包含max和min) 公式: ~n+1=-n; " ~ "是取反符號,代表0變1,1變0,例如~1010=0101; 注意,取反對稱規律是補碼規定的基礎上存在的規律,補碼並不是由這個公式得到的. 正數的補碼和原碼相同,即就是自身. 負數的補碼是自身取反加1,例如:-3的補碼就是~1101+1=0010+1=0011=3;
$$:注意:取反對稱並不是說是來求補碼的,因為這個公式只是表示上面圖一那樣的規律, 例如:對1(0001)取反加1就會得到-1(1111),但1的補碼是本身,並不是-1,所以在對補碼 的理解和取反對稱規律不能會為一談.
由於有了上面的認知,我們就能總結出如果想要求一個數n的二進位制,可以通過他的相反數來求得; 比如我想求-4的二進位制,那是多少呢? -4就是-4的相反數4取反加1;----> ~0100+1=1011+1=1100;即-4的二進位制為1100 so easy吧!!
這裡科普一下!!:(這是計算機的計數規則) 二進位制數的原碼,反碼,及補碼的表示. 1.機器數與真值 機器數:數在機器中的編碼表示; 真值:一半書寫表示的數; 符號位:代表正 負號; 因為在計算機運算中,數值和符號完全數字化,採用把各種符號位和數字一起編碼的方法
a–原碼錶示
在機器數中,符號位用0代表正數,用1代表負數,數值用二進位制表示.
例如:
[X]原=符號位+絕對值
若X=+1100110 則 [X]原=01100110
X=-1100110 則 [X]原=11100110
b--反碼錶示
機器數的反碼可由原碼得到,
正數:[X]反=[X]原
負數:[X]反=對[X]原出符號位外各位取反
栗子:
若 X=+1100110 則[X]反=01100110
X=-1100110 則[X]反=10011001
c--補碼錶示
機器數的補碼也可以由原碼得到.(其實可以理解為是通過反碼得到)
正數:[X]補=[X]原
負數:[X]補=[X]反+1
栗子:
若 X=+1100110 則[X]補=[X]原=01100110
若 X=-1100110 則[X]補=[X]反+1=10011001+1=10011010
##溢位規律: n+(max+1)*2=n n-(max+1)*2=n 為什麼要了解溢位呢?不是因為要利用溢位的結果,因為不管什麼溢位的結果都是沒有任何意義的, 我們之所以要去了解它,是因為只有瞭解它才能更好的避免工作中發生溢位的情況,溢位不是隨機的, 它是一個確定的結果
java中的最小單位是int,因為byte和short和char都是用int來存放資料,可以用Integer的靜態方法toBinaryString()實驗 該方法可以輸出一個int型別的二進位制數,Long也有toBinaryString()方法,其輸出就是輸出long型別的二進位制數.當然這裡int型別也行
二進位制的運算: 運算子: >>> >> << ~ & | — >>>:無符號右移運算,邏輯右移 — >> :右移運算,數學右移(帶符號右移) — << :左移運算 — ~ :取反運算 — & :and 與運算 — | :or 或運算
經典面試題: 優化演算法:n*8 答案:n<<3 注意: 後面乘數必須是2的整數倍數次冪才能優化,否則不行
二進位制的移位運算:就是在二進位制的基礎上對數字進行平移,在移位計算中,byte,short,char移位前都會自動轉化成int型別; 規定:int型別進行移位的時候,實際移動的次數是移動的次數和32的餘數.也就是說移動33次和移動一次是一樣的; long型別…64的餘數.
接下來都是用int型別來舉例子:
a—左移運算 <<
運算規則:把數字的二進位制形式所有的數字都向左移動對應的位數,高位移除捨棄,低位空位用0補齊;
例如: 3 << 2
3-->二進位制形式:00000000 00000000 00000000 00000011
向左移動2位得: 00000000 00000000 00000000 00001100 -->12=3*2^2
所以可以得到,在沒有溢位的情況下,正數負數,左移移位相當於乘以2的1次方,左移n次相當於乘以2的n次方.
即:x << y --> x*2^y
這裡就可以解釋上面的經典面試題了:n*8==n << 3; (是不是突然發現 << 很簡單啊)
b–數學右移 >>
運算規則:把數字的二進位制形式所有的數字都向右移動對應的位數,低位移除(捨棄).高位空位補符號位,正數補0,負數補1,
由於要保證正數移位後仍然是正數,負數移位後仍然是負數.
注意!:這裡的高位補符號位不是光之最高位,而是指向右移動了幾次,就要補幾個符號位.
例如: -11 >> 2
-11-->二進位制形式:11111111 11111111 11111111 11110101
向右移動2位得: 11111111 11111111 11111111 11111101 --> -3
右移一位相當於除以2的一次方,右移n位,相當於除以2的n次方,然後向下取整所得.
即x >> y --> Math.floor(x/2^y)
這裡如果不能整除,則是向下取整,向下取整的意思就是如果是小數,總會向最小的那個小數取整,舉個栗子:
-11 >> 3 --> Math.floor(-11/8)=Math.floor(-1.375)=-2
11 >> 3 --> Math.floor(11/8)=Math.floor(1.375)=1
c–無符號右移 >>>
運算規則:把數字的二進位制形式所有的數字都向右移動對應的位數,低位移除(捨棄),高位的空位補0,所以對於正數來說是一樣的
對於負數來說是不一樣的.其他結構和>>相同.
二進位制的邏輯運算:
a–and & 邏輯與運算
運算規則:將兩個運算元按位對齊,每個位置進行乘法運算,稱為與運算
與運算可以對資料進行拆分.
int n=100;
00000000 00000000 00000000 01100100
int m=15;(2的x次冪-1代表要擷取從n的尾部擷取x位數)
00000000 00000000 00000000 00001111
所以int i=n & m;-->
00000000 00000000 00000000 00000100
即從i的尾部擷取4位:0100;
與運算的用途:用於擷取一個數的特定數位
一個經典案例:將一個正數int拆分為4個byte
b–or | 邏輯或運算
運算規則:將兩個數對齊,上下位置數字進行邏輯加法,可用於將byte合併為int
邏輯加法: 0|0=0 , 0|1=1, 1|0=1, 1|1=1
或運算用途:用於對資料進行拼接;
所以,如果要拼接,那麼在拼接的位置上,有一方必須為零,因為如果雙方都為1,那麼結果還是1,
這樣就會覆蓋掉一方的資訊,對拼接有影響.
例如:
a= 00000000 00000000 10110101 00000000
b= 00000000 00000000 00000000 11010010
於是 a | b = 00000000 00000000 10110101 11010010
##十六進位制: 16進位制其實就是2進位制的縮寫,其產生的原因也是為了降低硬體生產成本;能更好的計數,計算機內部只用2進位制進行計算. 十六進位制的表達方式:(注意這裡字母大寫小寫都行)
2進位制 16進位制
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 a
1011 b
1100 c
1101 d
1110 e
1111 f
{16進位制分別對應的二進位制碼}
其中16進位制數是以0x開頭; -1用16進位制的表示: 1111 1111 1111 1111 1111 1111 1111 1111 0x f f f f f f f f -->0xffffffff 最大值max用16進製表示: 0111 1111 1111 1111 1111 1111 1111 1111 0x 7 f f f f f f f -->0x7fffffff 最小值min用16進製表示: 1000 0000 0000 0000 0000 0000 0000 0000 0x 8 0 0 0 0 0 0 0 -->0x80000000
綜合練習: 一:對顏色進行擷取 對顏色RGB進行擷取:-----------------下面給出兩種表達方式--------->>> 顏色的16進製表示: color=0x00b0d8f8 R(red) : 248 G(gree): 216 B(blue): 176 (RGB的數是用十進位制表示的) 第一步:0xe8b888 的二進位制形式–> 0000 0000 1011 0000 1101 1000 1111 1000 第二步:color & 255 -->就可以把最後八位擷取下來,即是代表R 第三步:把color向右移位,這裡可以用 >>,也可以用>>>,因為正數這兩個沒有影響,高位都是補0 這裡向右移動8位,因為把R擷取完,然後準備擷取G. --> color >>= 8; 第四步:color & 255 -->可取出G 然後 color >>= 8; 最後 :color & 255 -->可取出B
二:對顏色進行拼接
把顏色按照相反的順序依次拼接起來,插入順序: B-->G-->R
第一步:把B的二進位制做左移8位的操作,即:color=B << 8.
第二步:把B的左移結果和G的二進位制做或運算 color |= G 也就是拼接.並且color <<= 8;
第三步:把第二步的操作結果和R的二進位制做或運算 color |= R 也是進行拼接操作.
最後輸出的就是上面的.只不過IDE輸出的時候會自動在內部把二進位制轉化為十進位制
輸出的時候顯示的是十進位制數字,如果用Integer.toBinaryString()則可以看到輸出的二進位制
注意:如果前面有0,則IDE會直接把0去掉.
在網際網路的資料傳輸的時候,都是將資料拆分為byte然後進行傳輸,所以要對資料進行編碼和解碼. 而編碼和解碼都是對二進位制的編解碼操作.
文字的編碼: 將char資料拆分為byte資料,稱為文字的編碼,將byte資料合併為char型別資料稱為文字的解碼; UTF-16BE 將char拆成兩半,支援65535個字元,但是英文字元只佔一個位元組,即1byte,所以英文就會浪費一半的空間.
於是出現了UTF-8編碼,又稱為萬國碼. UTF-8:支援10萬字+ 的字元,是變長編碼,1-4個位元組編碼: 英文1位元組節省空間,中文正好佔位在3個位元組中間,但是Unicode讓中文實際佔用4個位元組位置(只是給中文字元加了特殊標誌) UTF-8:是國際最優編碼.
GBK:中國標準 也是變長編碼 1~2個位元組,英文1個位元組,中文2個一共20000+ 字元 GBK:是中國本地化最優編碼.