本系列文章經補充和完善,已修訂整理成書《Java編程的邏輯》,由機械工業出版社華章分社出版,於2018年1月上市熱銷,讀者好評如潮!各大網店和書店有售,歡迎購買,京東自營連接:http://item.jd.com/12299018.htmlhtml
上節咱們提到正整數相乘的結果竟然出現了負數,要理解這個行爲,咱們須要看下整數在計算機內部的二進制表示。編程
十進制swift
要理解整數的二進制,咱們先來看下熟悉的十進制。十進制是如此的熟悉,咱們可能已忽略了它的含義。好比123,咱們不假思索就知道它的值是多少。微信
但其實123表示的1*(10^2) + 2*(10^1) + 3*(10^0),(10^2表示10的二次方),它表示的是各個位置數字含義之和,每一個位置的數字含義與位置有關,從右向左,第一位乘以10的0次方, 即1,第二位乘以10的1次方,即10,第三位乘以10的2次方,即100,依次類推。post
換句話說,每一個位置都有一個位權,從右到左,第一位爲1,而後依次乘以10,即第二位爲10,第三位爲100,依次類推。spa
正整數的二進制表示code
正整數的二進制表示與此相似, 只是在十進制中,每一個位置能夠有10個數字,從0到9,但在二進制中,每一個位置只能是0或1。位權的概念是相似的,從右到左,第一位爲1,而後依次乘以2,即第二位爲2,第三位爲4,依次類推。htm
看一些數字的例子吧:blog
二進制 | 十進制 |
10 | 2 |
11 | 3 |
111 | 7 |
1010 | 10 |
負整數的二進制表示get
十進制的負數表示就是在前面加一個負數符號-,例如-123。但二進制如何表示負數呢?
其實概念是相似的,二進制使用最高位表示符號位,用1表示負數,用0表示正數。
但哪一個是最高位呢?整數有四種類型,byte/short/int/long,分別佔1/2/4/8個字節,即分別佔8/16/32/64位,每種類型的符號位都是其最左邊的一位。
爲方便舉例,下面假定類型是byte,即從右到左的第8位表示符號位。
但負數表示不是簡單的將最高位變爲1,好比說:
和咱們的直覺正好相反,這是什麼表示法?這種表示法稱爲補碼錶示法,而符合咱們直覺的表示稱爲原碼錶示法,補碼錶示就是在原碼錶示的基礎上取反而後加1。取反就是將0變爲1,1變爲0。
負數的二進制表示就是對應的正數的補碼錶示,好比說:
給定一個負數二進制表示,要想知道它的十進制值,能夠採用相同的補碼運算。好比:10010010,首先取反,變爲01101101,而後加1,結果爲01101110,它的十進制值爲110,因此原值就是-110。直覺上,應該是先減1,而後再取反,但計算機只能作加法,而補碼的一個良好特性就是,對負數的補碼錶示作補碼運算就能夠獲得其對應整數的原碼,正如十進制運算中負負得正同樣。
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。
十六進制
二進制寫起來太長,爲了簡化寫法,能夠將四個二進制位簡化爲一個0到15的數,10到15用字符A到F表示,這種表示方法稱爲16進制,以下所示:
2進制 | 10進制 | 16進制 |
1010 | 10 | A |
1011 | 11 | B |
1100 | 12 | C |
1101 | 13 | D |
1110 | 14 | E |
1111 | 15 | F |
能夠用16進制直接寫常量數字,在數字前面加0x便可。好比10進制的123,用16進製表示是0x7B,即123 = 7*16+11。給整數賦值或者進行運算的時候,均可以直接使用16進制,好比:
int a = 0x7B;
Java中不支持直接寫二進制常量,好比,想寫二進制形式的11001,Java中不能直接寫,能夠在前面補0,補足8位,爲00011001,而後用16進製表示,即 0x19。
查看整數的二進制和十六進制表示
在Java中,能夠方便的使用Integer和Long的方法查看整數的二進制和十六進制表示,例如:
int a = 25; System.out.println(Integer.toBinaryString(a)); //二進制 System.out.println(Integer.toHexString(a)); //十六進制 System.out.println(Long.toBinaryString(a)); //二進制 System.out.println(Long.toHexString(a)); //十六進制
位運算
位運算是將數據看作二進制,進行位級別的操做,Java不能單獨表示一個位,可是能夠用byte表示8位,能夠用16進制寫二進制常量。好比: 0010表示成16進制是 0x2, 110110表示成16進制是 0x36。
位運算有移位運算和邏輯運算。
移位有:
例如:
int a = 4; // 100 a = a >> 2; // 001,等於1 a = a << 3 // 1000,變爲8
邏輯運算有:
大部分都比較簡單,就不詳細說了。具體形式,例如:
int a = ...; a = a & 0x1 // 返回0或1,就是a最右邊一位的值。 a = a | 0x1 //無論a原來最右邊一位是什麼,都將設爲1
小結
本節咱們討論了整數的二進制表示,須要注意的就是負數的二進制表示,以及計算機進行二進制加減操做的過程,從而咱們就能理解爲何有的時候正整數計算會出現負數。
咱們一樣討論了整數的位運算,須要注意的就是無符號右移和有符號右移的區別。
理解了整數,那小數呢?
----------------
未完待續,查看最新文章,敬請關注微信公衆號「老馬說編程」(掃描下方二維碼),深刻淺出,老馬和你一塊兒探索Java編程及計算機技術的本質。原創文章,保留全部版權。
-----------
更多相關原創文章
計算機程序的思惟邏輯 (6) - 如何從亂碼中恢復 (上)?