二進位制負數的在計算機中採用補碼的方式表示。很多人很好奇為什麼使用補碼,直接使用原碼表示多好,看上去更加直觀和易於計算。然而事實告訴我們,這種直觀只是我們人類的一廂情願罷了,在計算機看來,補碼才是它們最想要的。那麼,為什麼計算機使用補碼更好,又是如何通過補碼來計算數值的呢?
我看過網路上很多解釋補碼的文章,幾乎一致的回答就是符號位不變,其他各位逐位求反再加一。在此我想說,這些都不是根本原理。誰都知道這麼求,數電第一章就明確寫了怎麼求,關鍵是為什麼這麼算,其中的原理是什麼?
1.什麼是補碼
這個沒有找到官方定義,只進行個人定義。
個人定義:補碼是計算機中用來表示負數,使得負數能夠使用加法器參與加法運算的一種碼。
加減是計算機中最常用的運算,加法一般使用加法器來實現,減法則使用減法器實現。那有什麼辦法可以將減法變為加法,這樣就可以讓系統只實現加法即可,答案就是補碼。
理解補碼最簡單的例子就是時鐘。
例1:假如乙個時鐘現在顯示的是10點鐘,如何將它調到6點鐘?
解:有兩種方法,一是向後撥8個小時,二是向前撥4個小時
在這個例子中,8 和 4 互為補數,也就是說4的補碼是8,8的補碼是4,而這個時鐘的模就是12
注意:可能有人會想,在往後調8個小時雖然也調到了6點,但是他實際上比原來日期多了12小時。是的,的確如此,但是你的時鐘有地方儲存了這多餘的12個小時嗎?答案是沒有,所以在你調完後,你沒有記錄這12個小時,換句話說,你把這溢位的12個小時自動捨棄了。當第二個人來檢視鬧鐘時間的時候,他看到的時間就是準的。
例2:乙個數的數值是11,他的模是16,那麼他的補碼是多少?
解:16-11 = 5,即補碼就是5。
2.模關於模沒有找到固定的定義,簡單來說模就是乙個迴圈的週期,在例1中,時鐘的乙個週期就是12,所以模是12。一周的模是7天,一天的模是24小時。模是補碼的乙個重要概念。
3.使用補碼運算
例316-13,模為32,使用補碼運算該算式。
解 (16 + (32-13))% 32 = 35 % 32 = 3
4.使用補碼進行二進位制運算
有看過數電基礎的都應該記得,第一章就有說明如何求二進位制補碼是如何運算的。正數的補碼即為自己,負數的補碼為符號位不變,其餘逐位求反再加1。
使用該定義,先通過例子求出數值,再對例子進行詳細講解,為什麼可以使用負數的補碼來運算。
例4 通過二進位制求15-11的值
要想讓減法變加法,必須轉換算式為 15 + (-11)
15為正數,符號位為0,二進位制表示為 01111
-11為負數,符號位為1,負數原始碼為 11011 ,補碼符號位不變,其餘逐位求反再 +1,即 10101
所以 15 + (-11) = 01111 + 10101 = 100100 捨棄最高位(與高位址位概念不同)溢位位,即00100,即+4
這是乙個最簡單的補碼演算法運算的例子,卻有很多不解之處。
1.為什麼負數 (-11 )逐位求反再+1就可以代表原來的數?
2.為什麼高位捨棄
3.為什麼符號位能夠參與運算
先看問題1,-11 先不考慮符號位,觀察11的二進位制表示,11使用二進位制表示是 1011,將1011 逐位求反 得到 0100,因為是逐位求反,1011 +0100 = 1111 ,而1111 + 1 = 10000,發現了什麼?10000是四位2二進位制數的模。為什麼10000是4位二進位制數的模呢?原理也很簡單,4位暫存器最高能表示什麼數?即0b1111 = 15 , 15 +1 =16 即溢位低四位歸 0,所有模為16。
所以不管幾位二進位制數,取反後得到的值加原碼會剛好的到所有的位都是1的二進位制數,再加一就剛好進製得到模。所以取反加一是無論如何都能取到補碼的。比如 :(原)101 + (補)((反)010 +1) = 8 ,(原)10 + (補)((反)01 +1)= 4。
所以,負數符號位不變,其餘逐位求反 +1 只是算出補碼最簡單的方法,而不是理論基礎。
前面提到過,使用補碼代替原碼,計算後模掉溢位得到數值就可以得到計算的值了。
再看問題2,為什麼高位捨棄,這個問題其實在例1中已經做了說明,因為你沒有儲存這個高位的空間,用最簡單的解釋來解釋就是,乙個4位的暫存器,只能儲存資料的低四位,最高第五位沒地方放,就像例1中多出來的12小時,沒有地方儲存,那麼就丟棄了,反正結果正確就行。可能有人會問,你說丟棄就丟棄嗎,丟了你怎麼保證是正確的?
重新再看一次例4,現在考慮符號位,將符號位加入運算。
15 - 11 = 15 + (-11),其中 -11 為 11011(加了一位符號位,所以模為 16 * 2^1) 他的補碼為 10101 = 21
所以 15 -11 變為 15 +21 = 36 (01111 + 10101) ,想想看,原先是減乙個數,變換後卻變成了乙個比減數更大的加數了,能不溢位嗎。所以要模掉溢位位 36 % 32 = 4 。仔細觀察被模數36 = 1 00100 你會發現,在資料高2位以前的所有高位都是32的倍數,所以用32進行模運算就會全部清0,這就是為什麼高位可以直接捨棄的原因,因為高位永遠會是模的倍數。
最後看問題3,為什麼符號位能夠參與運算,可能在這前面一直被符號位困擾,為什麼參與運算就沒有問題,看了這裡的解釋,我相信你講不會再被困擾。
符號位對於我對二進位制補碼的理解產生了很大的阻礙,我不明白為什麼符號位可以參與運算,而且算出來還是對的。花了不少時間理解了符號位的含義。我想說,符號位不變,其餘逐位求反 +1 這個定義很差。
首先放棄符號位就是計算機表示正數和負數用的這個思維,改成這樣理解,就會非常清晰:在有符號的資料型別中,第一位如果是0,那麼這個數值是正數原碼,第一位如果是1,那麼這個數值是負數補碼,這個數值是計算所得,而不是計算機設定的如此。
然後放棄負數補碼符號位不變,其餘逐位求反再+1這個方法,使用如下負數補碼的求法。乙個二進位制數值如果是正數,那麼將不變。如果是負數,那麼這個二進位制數最高位加一位0(如: 1010 變為 01010 ,位數變高一位,模需要乘2,即由16變32),對該數求補碼(01010 求補碼 10110) 。是不是發現,所謂的符號位不變,其餘逐位求反再加一和 在數值前面再加一位0,再所有位求反再+1的效果是一樣的,只要求反,最高位0肯定會變成1。一旦知道第一位是0或者1,也就確定了他是正數還是負數了,採用這種理解法,運算子可以加入運算也就理所當然了。(被減數 + 負數補數)% 負數補數的模 = 帶符號計算值 這樣的計算方式能保證所有的符號位都能參與運算。而符號位不變,其餘取反+1的解釋顯的符號位非常難以理解。
最後再看下重新思考這個運算思路,在運算中,如果遇到加法運算子,則直接運算子,如果遇到減法運算子,檢視減數是正數還是負數,如果是負數,從補碼反求原始碼,加入計算,如果遇到正數,則最高位加一位0,取反 +1 求補碼,加入運算。
到這裡補碼的原理就差不多講清楚了,無非是使用模進行轉化,但是我們站在十進位制的角度,去看二進位制的東西,的確會顯得相當費解。
內容有相互巢狀成分,閱讀後回顧前面的內容可能會更加深入理解。
還有很多特殊情況沒有考慮,只講解了最核心的內容。
以上內容**於:
二進位制中的運算子
1、按位與運算子(&)
規則: 0 & 0 = 0; 0 & 1 = 0; 1 & 1= 1; 即,兩位同為1即為1,否則0.
例如: 3 & 5 = 1 ----> 0011 & 0101 = 0001 即為1。
2.按位或預算符 (|)
規則: 0 | 0 = 0; 0 | 1 = 1;1 | 0 = 1; 1 | 1 = 1; 即,兩位同為0即為0,否則1。
例如: 3 | 5 = 7 ---> 00000011 | 00000101 = 00000111 即為 7。
規則:0^0 = 0,0^1=1,1^0=1,1^1=0 參加位運算的兩位只要相同為0,不同為1
例子:3^5 = 6(00000011^00000101=00000110)
特別的任意數 ^ 0 = 任意數.
規則:二進位制位0變為1,1變為0
規則:相當於乘以2
規則:相當於除以2
二進位制 補碼 運算
問乙個基本的問題。負數在計算機中如何表示?舉例來說,8在計算機中表示為二進位制的1000,那麼 8怎麼表示呢?很容易想到,可以將乙個二進位制位 bit 專門規定為符號位,它等於0時就表示正數,等於1時就表示負數。比如,在8位機中,規定每個位元組的最高位為符號位。那麼,8就是00001000,而 8則...
二進位制補碼運算
二進位制負數的在計算機中採用補碼的方式表示。很多人很好奇為什麼使用補碼,直接使用原碼表示多好,看上去更加直觀和易於計算。然而事實告訴我們,這種直觀只是我們人類的一廂情願罷了,在計算機看來,補碼才是它們最想要的。那麼,為什麼計算機使用補碼更好,又是如何通過補碼來計算數值的呢?我看過網路上很多解釋補碼的...
二進位制位運算子
二進位制位運算子用於直接對二進位制位進行計算,一共7個。i i 0 上面這行 的意思就是將i 不管是整數或小數 轉為32位整數。利用這一特性,可以寫乙個函式,將任意數值轉為32位整數。function toint32 x toint32 1.001 1 toint32 1.999 1 toint32...