补码、无符号数减法运算
1. 補碼
Two's Complement(二補數、補碼)是對二進制數的數學運算,運算過程為:對二進制序列每一位取反(0->1; 1->0),再加1。
| 011 | 100 | 101 |
| 010 | 101 | 110 |
| 111 | 000 | 001 |
2. 計算機中有符號數的表示
計算機中的數值類型分為整數型和浮點數型,有符號數在最高位設置符號位,其余低位均為數值位。數值位一律采用補碼形式存儲,并參與計算。采用補碼的形式表示有符號數至少有兩大好處。
- 符號位和數值位統一參與運算,不用區分正、負,加法和減法實現簡單;
- 數據的原碼和補碼之間的相互轉換不需要依賴額外硬件電路。
下面分別介紹有符號數的表示方法
2.1 整數
正整數
正整數的補碼是其二進制表示,與原碼相同。
例如,在整數類型占用4字節(32位)的系統中,+5的補碼是00000000 00000000 00000000 00000101。最高位0表示該數值為正數,其余31位表示數值大小。
負整數
負整數的補碼需要對其絕對值的二進制表示進行補碼運算。
例如,-5的補碼是11111111 11111111 11111111 11111011。最高位為1,表示該數值為負數,其余31位表示數值大小。
在進行運算時,CPU并不會區分是正數還是負數,而是直接進行計算,這正是前面介紹的符號位和數值位的統一。
例如,a=10, b=-5,則a+b的運算過程如下:
如果,a=1, b=5,則a-b首先轉換成加法a+(-b),再進行計算,過程如下:
a-b ==> a+(-b)00000000 00000000 00000000 00000001 (1) + 11111111 11111111 11111111 11110110 (-10) ===========================================11111111 11111111 11111111 11110111 (-9)對于正整數(最高位為1),將非符號位的二進制位直接轉換成十進制,就表示該正數的實際大小。如果一個數是負整數,如何將其補碼轉換成十進制大小呢?補碼運算即可。
例如上面的11111111 11111111 11111111 11110111,最高位符號位是1,所以該數為負數,補碼運算之后為00000000 00000000 00000000 00001001,大小為9,所以表示-9。
2.2 浮點數
pass
3. 為什么是補碼?
為什么兩個數相減a-b用補碼形式a+(-b)進行計算的結果是正確的?不妨看一下對b進行補碼的過程絕對值的二進制序列取反,再加1。取反在計算機的邏輯電路中就是開關的閉合狀態取反即可,即1->0,0->1。如果用數學算式表達的話,對一個bit位b的取反運算可以寫成
取反b = 1-b (*) b=0時,取反b為1,1-b=1; b=1時,取反b為0,1-b=0; 所以算是(*)可以表達取反運算綜上,a-b的計算過程可表達為(8bit為例)
a-b == a+(-b) == a+(11111111-b+1) == a+(b的補碼形式) 在8bit系統中,11111111 + 1 == 00000000,溢出。 所以,a+(11111111-b+1) = a+(0-b) = a - b可以看出,補碼運算的實現效果巧妙地利用了因計算機系統位數限制而產生的溢出現象。
4. 一個C++面試題
下面代碼打印多少?
#include <iostream>int main(int argc, char **argv)
{
std::cout << 25u - 50;
return 0;
}
答案是4294967271。
25u是unsigned int類型,50為int類型。在這兩種操作數進行-運算時,int被提升為unsigned int型,運算變為25u - 50u,結果也應該是unsigned int類型。經過對-50u進行補碼運算后帶入加法運算,-25的二進制表示形式被存入內存,即11111111 11111111 11111111 11100111(int為32位),在打印時按無符號數處理,則直接轉換成十進制正整數為4294967271。
11111111 11111111 11111111 11100111 = 2^31 + 2^30 + ... + 2^5 + 2^2 + 2^1 + 2^0 = 2^5(1-2^27) / (1-2) + 7 = 4294967271總結
以上是生活随笔為你收集整理的补码、无符号数减法运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宝丽来还是富士?
- 下一篇: Excel 中使用甘特图解决项目进度问题