為什麼-0的補碼是00000000?

都知道負數求補碼的方式是原碼求反碼,再加1,可是加1時符號位參與運算嗎?

以-0為例(也只有這一個例子) -0的原碼是10000000 反碼是11111111 補碼在反碼基礎上+1 如果符號位不參與運算,得到的是10000000(忽略溢出)

可是-0的補碼是00000000 是因為符號位參與了運算才導致這樣的嗎

很抱歉在知乎問這樣基礎的問題,但是網上有各種說法,很多都說符號位不參與運算,可這樣得到的的確該是10000000吧?


補碼本質是用來構成一個環,以實現一個同餘運算。你可以認為所有定位長的加減乘除都是處於同餘系情況下的:以32位整數為例,你取得的結果永遠是2^32次方的餘數,這與有無符號無關。

你叫加法器算一個1+2,然而加法器其實做的是個同餘加法,即

aequiv 1,(mod 4294967296)\
bequiv 2,(mod 4294967296)\
requiv a+bequiv 3,(mod 4294967296)

這樣的作用是無論有符號還是無符號的運算,都可以共用同樣的加法器(乘法器)。

然後我們知道,4294967296的餘數總共就4294967296種,分別是0~4294967295。但是我們希望表示一個負數,那怎麼做呢?

4294967295equiv -1, (mod 4294967296)equiv 4294967295, (mod 4294967296)

於是乎就用4294967295來表示了。考慮到取值範圍,以及為了方便區分,我們定義有一半的數是正數、一半的數是負數,恰恰就是二進位最高位為1則是負數,最高位為0則表示正數範圍,這個就是補碼的本質。至於補碼的計算方法,也就是取反加1,完全是因為:

x+^sim xequiv 4294967295,(mod 4294967296)

這與『符號位』無關,它的逆運算,其實求解的是

x+^sim x +1 equiv 0,(mod 4294967296)\
-x equiv ^sim x+1,(mod 4294967296)

所以說到底還是個同餘數論的問題。

所以你看,把x=0代入剛剛的同餘方程,

-0equiv ^sim 0+1equiv 4294967295+1equiv 0,(mod 4294967296)

完全成立。


負數的補碼形式等於對應的正數的原碼取反加一。

例如-1的補碼形式等於正1的原碼取反加1。以8位為例,正一的原碼為00000001,取反11111110,加一是11111111。

根據這個規律,-0的補碼形式等於對應的正數0的原碼00000000,取反為11111111,加1是00000000,答案仍然是0。

題主你把原碼的概念理解得不準確。應當使用對應的正數求原碼,而並不存在所謂帶符號位的負數原碼。在補碼體系里沒有符號位一說,雖然最高位為一的恰好是負數,但在補碼體系里它不是符號位,而是正常數據的一部分。


補碼錶示法里10000000是-128,沒有-0隻有0。


討論補碼就沒有-0這個概念了,補碼的存在意義就是為了消除-0


思考一下為什麼要反碼+1,目的就是為了正負相加值溢出後歸為0啊。

比如

+3表示為00000011

-3表示為11111100+1=11111101(反碼加1)

-3+3就是11111111+1溢出後就直接為0了

剛好符合-3+3=0的性質,多精妙的設定。

0的反碼只不過把溢出放在+1這個環節了。


除了-0這個特例以外,符號位是否參與運算並不影響結果,而在補碼中把-0剔除了,把10000000變成-128,其補碼是128,溢出了。從最終結果看,可以認為是符號位參與了運算,但是也可以認為是128超出表示範圍,結果未定義。

總之,符號是否參與運算對結果沒有影響,可以認為不存在-0。


-0沒有補碼


丟開教科書式的概念,想想為什麼要有補碼這個東西,為什麼符號位會產生。

定義:

原碼錶示法是機器數的一種簡單的表示法。其符號位用0表示正號,用:表示負號,數值一般用二進位形式表示。

機器數的反碼可由原碼得到。如果機器數是正數,則該機器數的反碼與原碼一樣;如果機器數是負數,則該機器數的反碼是對它的原碼(符號位除外)各位取反而得到的。

機器數的補碼可由原碼得到。如果機器數是正數,則該機器數的補碼與原碼一樣;如果機器數是負數,則該機器數的補碼是對它的原碼(除符號位外)各位取反,並在未位加1而得到的。

如果是為了考試,死記即可。但我總想搞清楚為什麼計算機裡面的數要這樣子表達?意義何在?-128的補碼為什麼是10000000?為什麼補碼有這麼奇怪的運算規則?計算機算減法的時候都需要從源碼到補碼的計算嗎?

思路

  1. 計算機裡面,只有加法器,沒有減法器,所有的減法運算,都必須用加法進行。
  2. 用補數代替原數,可把減法轉變為加法。出現的進位就是模,此時的進位,就應該忽略不計。
  3. 二進位下,有多少位數參加運算,模就是在 1 的後面加上多少個 0。
  4. 補碼就是按照這個要求來定義的:正數不變,負數即用模減去絕對值。

補充解釋一下「模」的概念,可以參照離散數學裡面的環:

考慮時鐘上時間的計算,假設現在時針指向數字3,若問「6小時前時針指向的數字是幾」,則可以:

1. 將時針逆時針撥動6格。

2. 將時針順時針撥動12 - 6 = 6格。

兩者的結果是一樣的。這裡稱12為「模」。

故有 3時 - 6個小時 = 3時 + (12 - 6個小時),這裡可以看到將減法轉換成加法的過程,即「加上模減去絕對值的差」。

所以,假設模是10,有效位數為1,當我們計算 9 - 7 的時候:

9 - 7 =&> 9 + (10 - 7) = 12,去掉最高的位後,得到2,這是正確的結果。

作者的意思是說,計算機裡面所有數都以補碼形式保存,加減運算都是補碼之間的加法運算。然後作者提出了一個我之前沒聽過的觀點:

補數 和 補碼的定義式 裡面,根本就沒有什麼符號位。這最高位的1、0是自然出現的,並不是由人來規定的。

的確,符號位在補碼運算裡面是「模」,本身並不帶符號的意義。因為計算機將加法轉換成加上一個「負數」,而負數又以補碼的形式表現。補碼比源碼多一位,從這多出來的一位可以推斷出原來數字的正負號,所以成為了符號位。也可以這樣認為,留出一位(不全部佔滿)的原因是要用「模」來表示正負數。

也就是說,不是特意留出一個符號位,用1和0來表示正負號。而是補碼運算可以用最高位來表示正負,所以符號位誕生了。

那麼為什麼-128的補碼是10000000?可以這樣理解。-128是一個負數,所以它的補碼是它的「模」減去它的絕對值,即:

100000000 - 10000000 = 10000000

那麼為什麼負數補碼等於源碼的反碼加一呢?可以這樣推導:

100000000 - 10000000
= (11111111 + 00000001) - 10000000
= 11111111 - 10000000 + 1
= 01111111 + 1 //反碼加一
= 10000000

由此我們得知,在計算機裡面所有的數字都以補碼形式存儲。127存成01111111,-127存成11111111,算減法就變成算加法了,儘管你看到的是「-」號。


可以參考一下這個:原碼、反碼、補碼的產生、應用以及優缺點有哪些?


-0的補碼,按你說是100000000,注意到一件事,這個數字只有8位,所以最高位1其實溢出了,就是00000000…


補碼沒有-0,本身也沒有-0這個數,有的只有0


符號位既可以參與運算,也可以不動,其他位取反加一。

對於負零,按一個位元組,即10000000,符號位不變,其餘取反的結果為11111111,末位加一即變成九位100000000,捨去首位,就變成了00000000。

如果直接取絕對值,那麼10000000,就變成了00000000,按位取反,11111111,加一,捨去首位,得到同樣的結果。

某軟院老師精心授予,現在給你也說說。


x=0011,~x=1100,1=0001;

x+~x+1=0011+1100+0001;

~x+1 =1100+0001;

~x =1100;

~x-x =1100-0011=1001;

-x =11001-1100=1101;

-x=1101=~x+1;

跟著C大的思路來回正負都驗證了一遍,以防萬一0和非0也各算了一遍,結論一致。


補碼運算不是連符號位都參與的么?考慮上符號位也就是正0的反碼加1,這樣就是00000000了


測試代碼:

if ((-0) == 0)

{

printf("0x%08x
", (-0));

printf("0x%08x
", (-33));

}

結果:

0x00000000

0xffffffdf

結論:

-0 == 0

0在計算機里是按照正數來算的。

而正數的原碼等於補碼。

手機碼字,不要討論格式問題。


有關計算機的很多基礎,一本書就可以比較好的讓你全方位理解。 編碼:隱匿在計算機軟硬體背後的語言。


我嘗試用我粗淺的知識來答一下,

關於補碼的實際性質,我們只考慮4位數的補碼的二進位中的3個數 -1、0、1。

他們用二進位補碼錶示為

1111=-1(10進位)

0000=0(10進位)

0001=1(10進位)

我們在實際運算中,-1+1=0,0+1=1,當我們用補碼代入的時候,結果依然正確,比如1111+0001=10000(1位溢出於是就是0000),0000+0001=0001。

補碼基於這樣一個事實,-1應為負整數中的最大的值。這樣計算機就能用加法器算減法。

補碼的計算方式應該是用0減去該負數的絕對值,比如-2,應當為0000-0010=1110(因為0000不夠減,可向前借1,相當於10000-0010).

至於為什麼我們能按位取反+1,這是基於這樣一個事實一個數和它的按位取反的結果相加,和一定是1111,即-1,因此x+x1=-1,於是x+x1+1=0即x1+1=0-x=-x。

例如0010+1101=1111,0010+1101+0001=(1)0000(溢出),1101+1=10000-0010=1110。

另外關於題主的提到大-0的補碼,如果僅僅按照按位取反的定義來的話,-0應當等於1000,但是1000實際上是1001-0001的結果,所以補碼沒有-0,實際值應當是1001-0001=-7-1=-8

因為補碼並不是按位取反+1來定義的,所以當你用按位取反+1來定義-0的時候肯定是錯誤的

參考:&<計算機組成與設計 硬體/軟體介面&>


實際上,從數學的角度,確實不存在-0。在一個有符號位的系統中,符號位的權值是-2^n。比如一個8位數的有符號數11111111(b) = -2^7+2^6+2^5+2^4.....+2^0 = -1 。所以很容易看不出10000000(b) = -128。


補碼就沒有-0這個東西啊。。。。補碼只有一個0的概念。


如果你學了彙編你就懂了,沒學彙編別人講給你聽,我覺得你還是會很迷茫的。有個好的彙編老師教你,別看小甲魚的。


推薦閱讀:

如何 硬體 軟體 都精通,或者說 都懂?
國內DFRobot和Seeed Studio兩家哪家生產的Arduino電路板質量更好???
友寶售貨機是全部自主研發么?
雲主機會不會出現硬碟壞掉的問題?
遊戲悍將的電源都是炸彈嗎?

TAG:硬體 | 計算機科學 | 計算機組成原理 |