java的int類型
Java的原始類型里沒有無符號類型,c語言int類型表示有符號整型,unsigned int無符號整型
int占4個字節,每個字節8位,占32位,取值范圍 -231~231-1,有32個0-1的二進制位。
左起第一位是符號位, 0表示正數,1表示負數 其余后面31位是數值位。
0 0000000000000000000000000000010
數字0的表示: 按照上面提到的符號,有兩種0的表示方法,即“+0”和“-0”。 實際上,在32位系統下int類型中,計算機已經強行規定數字0采用“+0”的表示方法,即00000000 00000000 00000000;而“-0”這個特殊的數字被定義為了-2^31。 因此我們看到32位系統下int類型的取值范圍中,負數部分比正數部分多了一個數字,正數的最大取值是231-1,而負數的最小取值是-231。正數部分之所以要減去1,是因為被數字0占用了,而負數部分不需要用來表示0,因此原本的“-0”就用來表示-2^31這個數字。
那么-1按照上面描述就是: 10000000 00000000 00000001 了?左起第一位是符號位1表示負數?右起第一位是數值1? 實際不是這樣的。這里就需要引入“補碼”了。
計算機中的符號數有三種表示方法,即原碼、反碼和補碼。三種表示方法均有符號位和數值位兩部分,符號位都是用0表示“正”,用1表示“負”,而數值位,三種表示方法各不相同。
原碼
最高位1表示負,0表示正,剩余位表示數值。
原碼的1: 00000000000000000000000000000001
原碼的-1:10000000000000000000000000000001
原碼不能直接參加運算,可能會出錯。例如數學上,1+(-1)=0 ,原碼計算則是
00000000000000000000000000000001+10000000000000000000000000000001=-2 是錯的。
原碼的符號位不能直接參與運算。
反碼
正數的反碼與其原碼相同;負數的反碼是對其原碼逐位取反,但符號位除外。
對於正數和“+0”而言,其原碼本身就是反碼,例如 8位二進制“+1”,其原碼與反碼都是00000001;
對於負數和“-0”而言,符號位與原碼中一樣,保持不變,其余位數逐位取反,1換成0,0換成1,例如 “-1”,其8位二進制原碼是1000 0001,其反碼是1111 1110;
那么我們是否已經可以正常進行運算了呢?
我們舉個三個例子:
例一:1+2=3(以8位二進制表示)
十進制 | 原碼 | 反碼 |
---|---|---|
1 | 0000 0001 | 0000 0001 |
2 | 0000 0010 | 0000 0010 |
結果(反碼) | 0000 0011 | |
結果(原碼) | 0000 0011 | |
結果(十進制) | 3 |
計算結果正確。
例二:1+(-2)=-1
十進制 | 原碼 | 反碼 |
---|---|---|
1 | 0000 0001 | 0000 0001 |
-2 | 1000 0010 | 1111 1101 |
結果(反碼) | 1111 1110 | |
結果(原碼) | 1000 0001 | |
結果(十進制) | -1 |
計算結果正確。
例三:1+(-1)=0
十進制 | 原碼 | 反碼 |
---|---|---|
1 | 0000 0001 | 0000 0001 |
-1 | 1000 0001 | 1111 1110 |
結果(反碼) | 1111 1111 | |
結果(原碼) | 1000 0000 | |
結果(十進制) | -0 |
計算結果為-0,問題來了,由於-0的存在,使得二進制與十進制的互換不再是一一對應的關系。
總結:由於-0這個問題的存在,會使得計算機需要增加額外的物理硬件配合運算,所以在計算機發展的早期就已經拋棄了使用反碼儲存數據。
補碼
補碼正是基於反碼的“-0”問題誕生的,可以解決這個問題。
補碼的計算方法是:正數和+0的補碼是其本身,負數則先計算其反碼,然后反碼加上1,得到補碼。
補碼換算為原碼的過程中,如果補碼是正數或者+0的補碼,則其原碼就是補碼本身;如果補碼是負數或者-0的補碼,則其原碼的計算方法是,先將補碼減掉1,得到反碼,再將反碼取反,得到原碼。
例一:1+(-1)=0
十進制 | 原碼 | 反碼 | 補碼 |
---|---|---|---|
1 | 0000 0001 | 0000 0001 | 0000 0001 |
-1 | 1000 0001 | 1111 1110 | 1111 1111 |
結果(補碼) | 0000 0000 | ||
結果(反碼) | 0000 0000 | ||
結果(原碼) | 0000 0000 | ||
結果(十進制) | +0 |
計算結果正確,+0即是數字0的唯一表示。
例二:1+2=3
十進制 | 原碼 | 反碼 | 補碼 |
---|---|---|---|
1 | 0000 0001 | 0000 0001 | 0000 0001 |
2 | 0000 0010 | 0000 0010 | 0000 0010 |
結果(補碼) | 0000 0011 | ||
結果(反碼) | 0000 0011 | ||
結果(原碼) | 0000 0011 | ||
結果(十進制) | 3 |
計算結果正確。
特別地,我們加入例四:(-1)+(-127)=-128
我們知道8位二進制的符號數的取值范圍是(-27)~(27-1),即-128~127。
十進制 | 原碼 | 反碼 | 補碼 |
---|---|---|---|
-1 | 1000 0001 | 1111 1110 | 1111 1111 |
-127 | 1111 1111 | 1000 0000 | 1000 0001 |
結果(補碼) | 1000 0000 | ||
結果(反碼) | |||
結果(原碼) | |||
結果(十進制) | -128 |
由於補碼1000 0000具有特殊性,計算機在編寫底層算法時,將其規定為該取值范圍中的最小數-128,其值與(-1)+(-127)的計算結果正好符合。
補充一點,8位二進制補碼1000 0000沒有對應的反碼和原碼,其他位數的二進制補碼與此類似。
int類型在內存中,以補碼的形式存儲。而且我們還知道了為何int類型的取值范圍中負數的最小值的絕對值比正數的最大值大1的原因,即-2^32的補碼是10000000 00000000 00000000,原本-0的位置被-2^32取代了
二進制數在內存中以補碼的形式存儲
正數:原碼、補碼和反碼都相同
負數:補碼符號位不變,其它位是對應正數的原碼取反加一
歡迎關注個人公眾號一起交流學習: