標籤:style blog http color java strong 資料 2014 問題
這裡先將二進位的計算可以分為兩類,加減運算與乘除運算,本篇討論的是加減運算。
(一)預備知識——資料在電腦的儲存與表示
從一個問題入手:java中byte(1位元組,8位)的取值範圍為:-2^7<=取值範圍<=2^7-1,或者寫成-128<=取值範圍<=127,為什麼呢?
疑問:按照我們一般認為,如果8位中一位作為符號,那麼應該是11111111<=取值範圍<=01111111,或者寫成-127<=取值範圍<=127,-128從何而來?
首先從原碼講起,原碼即為電腦中對數值的二進位表示,如 5用二進位表示為0000 0101 ;
其次就是反碼,顧名思義就是取反,對於正數來說,反碼與原碼相同;對於負數來說,反碼為原碼的各位取反(符號位除外),如(0011 0111)反= 0011 0111 (1101 0010)反= 1010 1101 ;
再次就是補碼,電腦中,數值一律用補碼錶示和儲存的,正數的補碼與原碼相同,負數的補碼為“其反碼+1”,如(0101 1101)補=0101 1101 (1101 0010)補=1010 1110
關於補碼,我們做進一步解釋:
(1)化減為加:
由於計算中的CPU只有加法器,沒有減法器,所以在電腦採用原碼做減法是會存在這樣的問題:對於1-1=0
看做1+(-1)=0 二進位表示 0001+1001=1001 變成了十進位的負1而不是0。補碼的出現很好的解決了這個問題,由於採用補碼運算,則補碼加法成為:[X+Y]補 = [X]補 + [Y]補同時,補碼的減法變為:[X-Y]補 = [X]補 - [Y]補 = [X]補 + [-Y]補 ;在此我們以減法為例說明補碼的優勢,還以上述為題為例:(0001)補+(1001)補 = 0001 + 1111 = 0000 (最高位的進位省略),這樣就順利得到了0
(2)10000000與00000000都是零嗎?——關於-128的由來
補碼還解決了原碼中存在兩個0 的問題(即+0 和 -0),以8進位為例,java中byte的取值範圍應該是-127~ -0和+0~ 127 即存在-0和+0 ,但是在兩個0轉換為補碼後,分別為10000000和00000000,00000000它還是0,但是我們人為地規定10000000表示-128,這就是上面取值範圍中-128的由來。這裡再強調一下,10000000和00000000都是補碼,而不是原碼。
(3)一開始的問題,我們得出了“符合邏輯”的疑問,這個問題又出在哪?
其實問題出在,我們一直在用原碼在看問題,而不是補碼。這裡先舉一個我再微博中說過的例子,形象地說明一下什麼是補碼:
“時鐘的例子:0時和6時差(10-6)=4時(順時針),但是你也可以這樣寫(10+6)-12=4時(逆時針),後一個式子中的6就是“補碼”,12表示“定長”,減12表示“溢出”。“定長”和“溢出”也是“化減為加”的關鍵。這是一個從高維空間看低維空間而變得更加簡潔的典型。”
我們再用一個實際的例子說明一下如何用“高維看低維”:
類比時鐘的例子,我們將表中的補碼稍微轉換一下位置,寫在一維數軸上,再將數軸收尾相連,就形成了一個新的“時鐘圓盤”。
那麼我們來試試一個例子:3-1=(011-001)原碼運算=(011+111)補碼運算=010=2
也就是說我們可以寫成3-1=2(順時針運算),也可以寫3+7-8=2(逆時針運算)
這就是用逾時空理論,從高維去看地位的一種解釋方法。
(二)加減法運算
(1)原碼到補碼的轉化:符號位是要單獨提取出來的,不參與“取反加一”。如:
(10000000)原轉化為補碼:
a.將0000000取反加一後,等於10000000
b.因為a得到的超過了七位,去掉a中10000000的1,再將題目中1給不上去。這裡強調的是題目中的1和a中的1是不同的。
(2)補碼的運算是連同符號位一起運算的。這裡順便提一下,二進位乘法的運算子號跟十進位乘法一樣,符號位另算。
二進位的計算(電腦為什麼採用補碼儲存資料)