首先我們需要區分的是什麼是有符號數和無符號數。
有符號和無符號的區別是一個有符號位,另一個沒有符號位.
沒有符號位的數字只能有0和正值,有符號位的數字可以有正零,負零和正數負數.
從這裡可以看出,有符號和無符號的區別就是是否能表示負數。
然後我們再來理解java虛擬機器所支援的所有整數資料類型-byte,short,int和long,他們都是帶符號的二進位補碼。
那麼為什麼會採用二進位補碼呢?
首先我們還是來看二進位補碼的概念:
負數的補碼就是對反碼加1,而正數不變,正數的原碼反碼補碼是一樣的.
即若要用補碼系統資料表示 -5,首先要將 5 的二進位進行反相運算,再加 1。
0000 0101 (5) -----1111 1010-----1111 1011 (-5) 補碼
然後我們再看一個例子:
( 1 ) - ( 1 )
( 1 ) + ( -1 )(00000001)+ (10000001) -----------------原碼計算= (10000010)= ( -2 )
顯然原碼對於負數的運算無效。
所以,補碼主要是針對2進位的負數運算產生的。
它的原理是什麼呢,我們可以看一個在《Code》裡面舉的例子:
253 – 176 = ???
可以看到,這個減法運算在個位的時候,就需要向前借位了,十分麻煩。
但是我們可以轉變一下思路,首先這是一個三位元,三位元的最大值是999。因此我們先用999減去減數176
999 – 176 = 823//這一步是得到他的反碼
然後,用被減數253加上上面求出來的這個值823加1
253 + (823 +1)= 1077
然後把這個值再減去1000,這樣就得到了77。
253+(999-176)+1-1000=77
然後我們再來看二進位補碼計算:
0011 (3) //正數的補碼是它本身 + 1111 (-1) //負數的補碼是反碼加1 即0001》1110+1》1111-------------- 10010 (2)
結果 10010 似乎是錯的,因為已經超過四個位元,不過若忽略掉(從右數起的)第 5 個位元,結果是 0010 (2),和我們計算的結果一樣。而且若可以將二進位的 0001 (1) 變號為 1111 (-1),以上的式子也可以計算減法:3-1 = 2。
補碼的工作原理
學習電腦科學的學生會問:為什麼補碼能這麼巧妙實現了正負數的加減運算?答案是:指定n位元字長,那麼就只有2n個可能的值,加減法運算都存在上溢出與下溢出的情況,實際上都等價於模2n的加減法運算。這對於n位元不帶正負號的整數類型或是n位元有符號整數類型都同樣適用。
例如,8位不帶正負號的整數的值的範圍是0到255. 因此4+254將上溢出,結果是2,即。
例如,8位有符號整數的值的範圍,如果規定為−128到127, 則126+125將上溢出,結果是−5,即。
對於8位字長的有符號整數類型,以28即256為模,則
\begin{align}
-128 & \equiv 128 \pmod{256} \\
-127 & \equiv 129 \pmod{256} \\
\vdots \\
-2 & \equiv 254 \pmod{256} \\
-1 & \equiv 255 \pmod{256} \\
\end{align}
" data-media-type="image" data-inited="true">
所以模256下的加減法,用0, 1, 2, …, 254,255表示其值,或者用−128, −127,… , −1, 0, 1, 2,… ,127是完全等價的。−128與128,−127與129,…,−2與254,−1與255可以互換而加減法的結果不變。從而,把8位(octet)的高半部分(即二進位的1000 0000到1111 1111)解釋為−128到−1,同樣也實現了模256的加減法,而且所需要的CPU加法運算器的電路實現與8位不帶正負號的整數並無不同。
實際上對於8位元的儲存單元,把它的取值[00000000, …, 11111111]解釋為[0, 255], 或者[-1, 254], 或者[-2, 253], 或者[-128, 127], 或者[-200, 55], 甚至或者[500, 755], 對於加法硬體實現並無不同。
Since bytes have such a small range, they're often converted to ints in calculations and method invocations. Often, they need to be converted back, generally through a cast. Therefore, it's useful to have a good grasp of exactly how the conversion occurs.
Casting from an int to a byte for that matter, casting from any wider integer type to a narrower typetakes place through truncation of the high-order bytes. This means that as long as the value of the wider type can be expressed in the narrower type, the value is not changed. The int 127 cast to a byte still retains the value 127.
On the other hand, if the int value is too large for a byte, strange things happen. The int 128 cast to a byte is not 127, the nearest byte value. Instead, it is -128. This occurs through the wonders of two's complement arithmetic. Written in hexadecimal, 128 is 0x00000080. When that int is cast to a byte, the leading zeros are truncated, leaving 0x80. In binary, this can be written as 10000000. If this were an unsigned number, 10000000 would be 128 and all would be fine, but this isn't an unsigned number. Instead, the leading bit is a sign bit, and that 1 does not indicate 27 but a minus sign. The absolute value of a negative number is found by taking the complement (changing all the 1 bits to 0 bits and vice versa) and adding 1. The complement of 10000000 is 01111111. Adding 1, you have 01111111 + 1 = 10000000 = 128 (decimal). Therefore, the byte 0x80 actually represents -128. Similar calculations show that the int 129 is cast to the byte -127, the int 130 is cast to the byte -126, the int 131 is cast to the byte -125, and so on. This continues through the int 255, which is cast to the byte -1.