java int類型底層存儲&原碼&反碼&補碼


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取代了

二進制數在內存中以補碼的形式存儲

正數:原碼、補碼和反碼都相同

負數:補碼符號位不變,其它位是對應正數的原碼取反加一

歡迎關注個人公眾號一起交流學習:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM