我們都知道計算機中的負數是用補碼來表示的,而負數的補碼是原碼符號位不變,其他位按位取反再加一。但是為什么必須這樣?為什么非要取反再+1?這個定義是怎么來的?
首先我們用我們熟悉的十進制來思考問題,假設現在我們只考慮兩位數字的運算,比如56 + (-28) = 56 - 28,這里如果作正常的減法運算,就需要借位,也就是先讓"6"減去"8"的時候,發現不夠減,所以要向高位“借一位”,所以"5"只能借一位給“6”,然后“5”變成“4”,這樣的“借位規則”如果用電路來實現,會很復雜(至於如何用電路實現,感興趣的同學可以去看《Code》的一到十二章),但幸運的是我們有辦法來避免這樣的借位:
56 + (-28) = 56 - 28 + 99 - 99 //加99再減99表達式值不變
= 56 - 28 + 99 + 1 - 100 //把-99寫成1 - 100
= (99 - 28 + 1) + 56 - 100 //交換一下位置
如上面最后一步所示,如果按照其從左到右的順序依次運算,是完全不需要借位的,這里的99其實可以看成“兩位數字能表示的最大的數值“,如果是三位數字,那就是999。最后在減去100之前,其實已經”溢出“了,這時候只要把最高位舍去就行了。
換到二進制也是一個道理,假設我們只能用八位數字來表示一個數值,那么上面的28寫成二進制就是00011100,然后我們要用“八位數字能表示的最大的數值”減去它,就是11111111 - 00011100,這時候你會發現,這樣做的結果剛好就是00011100全部都取反一下(0變1,1變0),變成11100011,然后再加一變成11100100,這時候再加上56(也就是二進制的00111000):
11100100
+ 00111000
------------
100011100
然后把結果中多出來的一位最高位舍去,就得到了00011100,也就是十進制的28(56 - 28 = 28)!
寫到這里我想大家應該已經明白了,只要把-28(二進制的-00011100)用72(二進制的11100100)來表示,就能直接用加法得到正確結果了。這也是為什么負數的符號位是1的原因,因為,比如用八位二進制來表示一個數值,如果要包含負數的話,那我們只能舍棄一半原來的正數,讓這部分正數來表示負數,很自然地我們用“更大的那一半”來表示負數,比如原來可以表示0到256,現在我們就把128到256“分給負數”,剩下的0到127繼續表示正數(如果用128到256來表示正數,0到127表示負數,那么0到127和-127到0這部分數值就沒人表示了)。所以,“一串01”在計算機中到底表示幾,還得看它能不能表示負數。