說明
在看JDK源碼的過程中,可以看到很多關於位運算的內容,位運算當然涉及計算機中二進制數字的存儲方式以及值之間的轉換,本文介紹一下二進制的三種表示方式:原碼、反碼、補碼。
概念
原碼: 將最高位作爲符號位(0表示正,1表示負),其它數字位代表數值本身的絕對值。
反碼:正數的反碼和原碼相同
。如果是負數,則將原碼符號位不變
,其餘各位取反,得到的就是負數的反碼。
補碼:正數的補碼和原碼相同
。如果是負數,則將原碼符號位不變
,其餘各位取反,然後將得到的數值加1(負數的補碼也可以理解成反碼加1)。
示例
通過上面的介紹,我們已經知道了幾種二進制碼之間的關係,下面用一個示例更直觀表示一下。爲了計算方便起見,假設計算機存儲的是8位
下的值。
十進制數 | 原碼 | 反碼 | 補碼 |
---|---|---|---|
+127 | 0111 1111 | 0111 1111 | 0111 1111 |
+1 | 0000 0001 | 0000 0001 | 0000 0001 |
+0 | 0000 0000 | 0000 0000 | 0000 0000 |
-0 | 1000 0000 | 1111 1111 | 0000 0000 |
-1 | 1000 0001 | 1111 1110 | 1111 1111 |
-127 | 1111 1111 | 1000 0000 | 1000 0001 |
總結一下:
正數的原碼、反碼、補碼是相同的
。- 負數的反碼是
符號位不變
,其餘按照原碼按位取反,負數的補碼是反碼加1; - 計算機運算以及存儲都是基於
補碼
形式。 - 0的補碼只有唯一表示
0000 0000
- -128沒有原碼和反碼,因爲已超表示範圍,
原碼和反碼區分正0負0,但是補碼不需要
,空出來的這個位置用來表示-128即1000 0000 - 8位有符號數值的範圍爲
[-128,127)
注意包含-128
計算機中二進制爲什麼使用補碼錶示
這裏面牽扯到一個很重要的計算方式模
運算。通過模運算實現化減爲加
,本質上是將溢出的部分捨去而不改變計算結果。
8位運算的模爲256=2^8。
在無符號位的情況下:127+2=129
129超出了8位運算的最大表示範圍,所以上面的二進制的結果1000 0001表示的轉換爲原碼爲1111 1111即爲-127。意思就是說129在計算機中的表示和-127是一樣的,就像是時鐘過了12點重新從0點開始了,超過了最大的數就從最小的數開始,256類似於時鐘的一圈。
這裏我們可以得出結論:負數的補碼爲模減去該數的絕對值
以-3爲例:
-3原碼:1000 0011
-3反碼:1111 1100
-3補碼:1111 1101
使用模運算計算結果:-3=256-3=253=1111 1101(二進制)
根據下面的例子我們看一下補碼是如何化減爲加
的
127-3=127+(-3)=124=0111 1100(二進制)
由於我們存儲的是8位,因此溢出捨棄
得到的是0111 1100=124(十進制),因此補碼的化減爲加核心是通過溢出捨棄
操作來完成的。