一道C++面試題和補碼、無符號數(shù)減法運算

面試題在文章第4節(jié)。在看面試題之前,可以先看一下1-3節(jié)的知識點。

1. 補碼

Two's Complement(二補數(shù)、補碼)是對二進制數(shù)的數(shù)學運算,運算過程為:對二進制序列每一位取反(0->1; 1->0),再加1。

bits 取反 補碼
011 100 101
010 101 110
111 000 001

2. 計算機中有符號數(shù)的表示

計算機中的數(shù)值類型分為整數(shù)型和浮點數(shù)型,有符號數(shù)在最高位設置符號位,其余低位均為數(shù)值位。數(shù)值位一律采用補碼形式存儲,并參與計算。采用補碼的形式表示有符號數(shù)至少有兩大好處。

  • 符號位和數(shù)值位統(tǒng)一參與運算,不用區(qū)分正、負,加法和減法實現(xiàn)簡單;
  • 數(shù)據的原碼和補碼之間的相互轉換不需要依賴額外硬件電路。

下面分別介紹有符號數(shù)的表示方法

2.1 整數(shù)

正整數(shù)

正整數(shù)的補碼是其二進制表示,與原碼相同。
例如,在整數(shù)類型占用4字節(jié)(32位)的系統(tǒng)中,+5的補碼是00000000 00000000 00000000 00000101。最高位0表示該數(shù)值為正數(shù),其余31位表示數(shù)值大小。

負整數(shù)

負整數(shù)的補碼需要對其絕對值的二進制表示進行補碼運算。
例如,-5的補碼是11111111 11111111 11111111 11111011。最高位為1,表示該數(shù)值為負數(shù),其余31位表示數(shù)值大小。

在進行運算時,CPU并不會區(qū)分是正數(shù)還是負數(shù),而是直接進行計算,這正是前面介紹的符號位和數(shù)值位的統(tǒng)一。
例如,a=10, b=-5,則a+b的運算過程如下:

  00000000 00000000 00000000 00001010 (10)
+ 11111111 11111111 11111111 11111011 (-5)
===========================================
  00000000 00000000 00000000 00000101 (5)

如果,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)   

對于正整數(shù)(最高位為1),將非符號位的二進制位直接轉換成十進制,就表示該正數(shù)的實際大小。如果一個數(shù)是負整數(shù),如何將其補碼轉換成十進制大小呢?補碼運算即可。
例如上面的11111111 11111111 11111111 11110111,最高位符號位是1,所以該數(shù)為負數(shù),補碼運算之后為00000000 00000000 00000000 00001001,大小為9,所以表示-9。

2.2 浮點數(shù)

pass

3. 為什么是補碼?

為什么兩個數(shù)相減a-b用補碼形式a+(-b)進行計算的結果是正確的?不妨看一下對b進行補碼的過程絕對值的二進制序列取反,再加1。取反在計算機的邏輯電路中就是開關的閉合狀態(tài)取反即可,即1->0,0->1。如果用數(shù)學算式表達的話,對一個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系統(tǒng)中,11111111 + 1 == 00000000,溢出。
所以,a+(11111111-b+1) = a+(0-b) = a - b

可以看出,補碼運算的實現(xiàn)效果巧妙地利用了因計算機系統(tǒng)位數(shù)限制而產生的溢出現(xiàn)象。

4. 一個C++面試題

下面代碼打印多少?

#include <iostream>

int main(int argc, char **argv)
{
    std::cout << 25u - 50;
    return 0;
}

答案是4294967271。

25uunsigned int類型,50為int類型。在這兩種操作數(shù)進行-運算時,int被提升為unsigned int型,運算變?yōu)?code>25u - 50u,結果也應該是unsigned int類型。經過對-50u進行補碼運算后帶入加法運算,-25的二進制表示形式被存入內存,即11111111 11111111 11111111 11100111(int為32位),在打印時按無符號數(shù)處理,則直接轉換成十進制正整數(shù)為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

更多面試題和答案:24 Essential C++ Interview Questions

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容