我們都知道java 的byte佔4個字節,1個字節8位。而計算機表示數據都是以二進位的形式表示。那麼一個byte表示的二進位應該為0000 0000 -1111 1111,又因為最高位代表符號位,那麼一個byte表示的範圍就應該為(-2^7-1)-(2^7-1)即-127到127怎麼會有-128呢?
其實也沒有什麼好說的,這就是規定的,包括short,int,long這些都是一樣!那麼為什麼這麼規定呢?有興趣的可以繼續往下看。我們一步一步的分析:
1.計算機沒有減法運算,所謂的做減法其實是通過加法來運算的。那麼怎麼將減法變成加法來運算呢?這裡涉及到一個模的概念。通常的解釋就是用的一個鐘錶來解釋的。
比如現在是3點鐘,我們現在要讓它指到1點,我們可以怎麼辦呢?有兩種方式:
將時針往後撥兩個小時即 3-2=1;將時針順時針撥10個小時即3+10同樣指向了1點。是否明白了一點呢,計算機將減法變成加法採用的主要就是這種方式!
那麼計算機怎麼將3-2變成3+10的呢,怎麼求出這個10的呢。這裡就涉及到了一個模,在這裡這個模就是12。這個12在這個時鐘中就代表最大值,通過12-2就是等於10了。當然剛說了計算機沒有減法,這裡自然不會是12-2這麼算。需要清楚計算機怎麼算的繼續往下看:
我們都知道計算機裡負數是以補碼的形式存在的,正數的補碼是其本身,計算機加法是補碼相加。
這裡需要重溫一下:
負數的補碼是其反碼加1.負數的反碼是除符號位外,其餘位數安位取反。正數的補碼,反碼,原碼均相同。那麼我們來看看(byte)(3-2)這個在計算機裡面是怎麼計算的呢?我們這裡是以byte來討論的所以是以8位二進位來表示:
3->0000 0011(原/反/補)
(-2)->1000 0010(原)->1111 1101(反)+1->1111 1110(補碼)
所以3-2=0000 0011+1111 1110(補碼)按位相加=0000 0001(補碼)(符號位相加溢出留0)
注意:補碼相加時符號位進行了計算的。
上面的0000 0001就是3-2在計算機裡保存的結果,還需要轉換為原碼,因為符號位是0代表正數,原碼也是0000 0001所以顯示為10進位就是1.
看了上面的過程,我們來梳理一下,計算機為什麼要將負數保存為補碼的形式。
我們之前看了關於時針的問題即3-2=3+10等於1點。
那麼計算機將負數變成補碼也是這個原因,希望通過與補碼相加來將減法變成加法,因為計算機沒有減法。
我們上面看了,時針的模是12那麼byte的模是多少呢?我們可以通過計算獲取,參照
3-2=1;
3+10=13;
那麼根據時鐘的模就是10+2等於12的計算方式:
同理計算機中: 3-2=0000 0011+1111 1110(補碼)
其中0000 0011+1111 1110(補碼)類比上面的3+10;
那麼btye的模=1111 1110(補碼)+0000 0010(2的原碼)=1 0000 0000(2的8次方)=256,(注意此處沒有區分符號位,因為計算機計算補碼相加時符號位也是相加了的,需保持一致)這樣在byte範圍內計算結果才不會出問題。不過你會發現有9位了,對就是9位。但這並不影響因為它只是byte類型計算時用的模,只要byte類型的數值是在8位以內就行。
那麼我們再反過來看,為什麼時鐘上 3+10=13與3-2=1相等了呢,顯然是因為13再減去了個12即13-12(模)=1.
那麼表現在計算機中就相當於溢出,即3-2=0000 0011+1111 1110(補碼)按位相加=1 0000 0001(補碼)然後捨去了1 0000 0000(模)(因為只有8位)=0000 0001(補碼)。
其實模的值是先確定好了的。我們會發現模其實就是等於2的n次方,n代碼數據類型的位數。那麼我們就不難理解為什麼負數的補碼是原碼的反碼+1了,因為這樣處理,補碼加上無符號原碼就剛好等於模即10000 0000(byte類型的模的二進位)
我們還可以根據上面推算出:補碼=模-負數的絕度值
感覺有點跑題了。總之計算機將減法轉換為加法的思想就是採用了模的思想!
那麼我們繼續看看為什麼btye最小值是-128不是-127呢?
原因是:1000 0000 表示 -0 而又有0000 0000表+0
-0顯然沒有任何意思,那麼就規定1000 0000表示成-2的7次方。這樣還可以多表示一位。
那麼用它表示-128來計算有沒有問題呢,答案肯定是沒有的,不然經過這麼久了,怕是早就出問題了。但是為什麼不會出現問題呢?
我們按平常的思路來看-128首先是個負數那麼除符號位外取反+1再保留8位的補碼是0000 0000
那麼-128+1=0000 0000+0000 0001 = 0000 0001 =1
結果顯然不對,為什麼不對,因為既然1000 0000 表示-128我們肯定不能按平常思路來算 因為正常來算的話 11000 0000才應該表示-128.
問題出在了-128的補碼計算方式上,我們可以根據上面的公式計算補碼為:模-負數的絕度值。
既然為-128那麼絕對值肯定為128。所以-128的補碼為 1 0000 0000 - 1000 0000= 1000 0000 即其本身
那麼此時 -128+1=1000 0000+0000 0001 = 1000 0001 (補碼)
再轉換成原碼1111 11111顯示出來即-127。結果正確 !
至此,結束,歡迎留言討論!