1. 程式人生 > >補碼(為什麽按位取反再加一):告訴你一個其實很簡單的問題

補碼(為什麽按位取反再加一):告訴你一個其實很簡單的問題

滿足 所有 我們 進位 數字 樂意 如果 二進制 關系

  首先,閱讀這篇文章的你,肯定是一個在網上已經糾結了很久的讀者,因為你查閱了所有你能查到的資料,然後他們都會很耐心的告訴你,補碼:就是按位取反,然後加一。準確無誤,毫無破綻。但是,你搜遍了所有俯拾即是而且準確無誤的答案,卻仍然選擇來看這篇毫不起眼的文章,原因只有一個,只因為你還沒有得到你想要的東西。

  因為你想要的,不是1+1=2,而是,1+1為什麽等於2。當然,我們不討論1+1的問題。我們討論的,是補碼。

你已經困惑了很久,你明明知道補碼就是按位取反,然後加一,但是你想知道的,不是它怎麽求滴,而是,它怎來滴。當然,對於閱讀這篇文章的你,既然想要知道這個答案,一定是有一定編程基礎的讀者,肯定知道補碼與有符號數與無符號數的關系(有符號數指帶有正負號的數,無符號可以理解為只大於0的數),你所查閱的所有資料首先都會用一個8位的二進制數給你舉例,ok,我們也用一個8位的二進制數。

  8位二進制數,最小00000000,最大數11111111,換算十進制為0~255,當然,所有的參考資料都會這樣講,而且這也不是你想要的,但我們必須說下去。1~255,一共255的字符,再加上最前面的0,一共256個字符。現在,我們要用一個8位二進制數字來表示一個負數,可是二進制裏沒有負號,誰都知道二進制裏只有0,1,再無其他符號。那麽所以我們必須用一種方式來代替正負,也就是我們規定,當然是人規定的,而不是電腦,我們規定這個8位的二進制數的最前面一位數來表示這個數的正負,0代表是正,1代表是負。那麽當第一位是0時,我們一共可以表示00000000~01111111這麽多正數,因為第一位必須是0來代表正數;當第一位是1時,我們一共可以表示10000000~11111111這麽多負數,然後,我們用00000000~01111111來代表0~127,那豈不是10000000~11111111代表 -0 ~ -127??可是網上都說不能有 負0,可是我覺的沒什麽不妥啊,負0不還是0 嗎?10-0=10,不就是相當於10+(-0)=10嗎,現在我們不討論正負0的問題,我們來討論一個小學生的問題。

  我們現在要把00000000~11111111分成兩組數,一組是正數,另一組是負數,正數是0,1,2,3,4,5,6,7,8,… 負數是 -1,-2,-3,-4,-5,-6,-7,-8,… 那麽這裏就有一個小學問題,那就是1+(-1)肯定要等於0,2+(-2)=0,他們是相反數,相加等於0,小學生都會。後面都是一樣,那麽現在我們使用上面的編碼的方式進行一個計算,現在上面的編碼中 1 對應的二進制是00000001,-1對應的二進制是10000001,然後你把這倆二進制數加起來,看看等於幾,對,答案是10000010,不是00000000,也不是10000000, 10000010在上面的編碼中代表 -2,00000000和10000000都在上面代表0,可是結果並不是他們。而00000001與10000001分別對應著1和-1,加起來理論的結果應該是0才對,也就是說上面的編碼是錯誤的。

  或許接下來很多資料又討論了反碼,但是我們不,我們來求一個一元一次函數,一個小學的函數,1+x=0,求x=?,答:-1。沒錯,而且準確無誤。那麽現在問題來了,前面的正數編碼應該是沒有錯的,00000000代表0, 00000001代表1,這些都符合我們的習慣,那麽出錯的是在後面的負數編碼上,我們到底該如何編碼對應負數編碼它才能正確呢,因為我們知道1+(-1)必須等於0,也就是他們對應的二進制相加也必須等於0,1對應00000001,那麽00000001+x=00000000,裏面的x就應該代替 -1的二進制編碼才對,這樣,我們得到 x=11111111,大家看一下這和按位取反,然後加一的結果一樣嗎。

  所以我們的結論是,一個正數對應的負數(也就是倆相反數),這兩個數的二進制編碼加起來必須等於0才對,所以我們只要知道其中一個數的編碼x,然後用0-x就是他對應的數的編碼,這樣的話,從0~127,我們用(0 - 其中一個二進制數的編碼)=(另一個二進制數的編碼),例如 2 的二進制編碼是00000010,那麽-2 的二進制編碼就是0 - 00000010=11111110,因為他就應該這樣,因為它就是一個小學問題,他倆加起來就應該等於0。那麽1000000對應的編碼是多少呢,當然也必須滿足加起來等於0才行,那麽10000000+x=0,求解x,答x=10000000,還是它本身,也就是在00000000~11111111這個範圍裏所有的二進制數都無法滿足它,也就是沒有一個數加上它等於0,但是兩個數要有對應的編碼,就必須加起來等於0才行,其實不止它沒有,0也沒有,0+x=0,那麽x=0,也是它本身,既然這樣了,那麽也沒有辦法了,無可奈何只能做單身漢了,然後我們規定,既然10000000第一位是1,代表負數,那麽我們規定它是一個負數,那麽10000000就代替了-128,而且,它只自己一個人,也就是只有-128,沒有正數128。

  然後,他們每個數都有了自己對應的編碼,而且準確無誤。1~127對應-1~ -127,再加上兩個單身漢0和-128。然後呢,不知道誰起的名字,就把這種編碼叫做了補碼,如果你樂意,你也可以給它起個名字。但是呢,還有一個問題,為什麽補碼的求法是按位取反再加一呢,其實當你不明白為什麽各大書籍都要用按位取反來計算補碼的時候,我們完全可以直接用0減去它就得到他相反數的二進制編碼了,譬如隨便一個十六進制數 6C ,那麽我們可以直接0-6C就得到他的相反數的補碼了,結果為十六進制的94,跟按位取反再加一的效果一樣。

  現在我們知道補碼是怎麽來的了,也就是為了保證兩個相反數對應二進制的和必須是0,然後又不知道誰給它起了補碼這個名字。補碼補碼,有沒有感覺兩個相反數是互補的呢,也就是任意兩個相反數加起來一定等0,其中一個數變大,另一個就一定會變小互補保證結果為0。但是你肯定還在糾結,為啥要按位取反,為啥還要加一呢。其實,這涉及到一個二進制減法的問題,你既然知道補碼這個概念,就一定會知道有進位丟失這麽個東西。現在我們知道了補碼是怎麽來的,也就是(00000000 - 其中一個正數的補碼)=(這個數相反數的補碼),那麽我們知道了1的二進制是00000001,那麽我們來求-1的補碼,也就是應該00000000 - 00000001=?,我們該怎麽計算這個二進制減法呢,而且還是一個小數減去大數,連借位都沒地方借,前面我們提到進位丟失這個東西,那麽我們來計算一個算式,11111111+00000001=?知道進位丟失的你,肯定知道加起來後等於00000000,雖然結果應該是100000000(後面是8個0),但是只能有8位,所以最高位的1丟失了,那麽現在好了,也就是說,我們可以把00000000看做(11111111+00000001)因為他倆是相等的,我們已經計算過的了,那麽我們現在就可以把前面講的公式中的00000000換成(11111111+00000001),也就是我們要計算-1的補碼,我們就0-1的編碼,也就是00000000-00000001,也就是(11111111+00000001)-00000001=(-1的補碼),這個算式我覺的你應該會計算了,大數減小數,到現在,或許你現在已經發現什麽了,是的,你發現了之前一直迷惑你的一個東西,“按位取反再加一”,但是可能還有一點迷惑,我們繼續,因為我們每次都是用一個0減去一個數的補碼來得到另一個數的補碼,也就是裏面的(11111111+00000001)是不變的,因為它就是0,那麽我們現在要求一個數的補碼,就是(11111111+00000001)- 一個數的補碼=它相反數的補碼,咱們把括號去掉,也就是11111111 - 一個數的補碼+00000001=它相反數的補碼,這是加法交換法則,只是把位置交換一下,小學生都會的,然後呢再加個括號方便我們理解,也就是(1111111 - 一個數的補碼)+00000001=它相反數的補碼。好了,問題來了,(11111111 - 一個數的補碼)的結果是什麽,這個你心裏應該是清楚的,你也可以算一下,它正好的等於它的反碼,也就是按位取反的一個數,其實也好理解,你減幾個數就看見規律了,描述好麻煩,現在好了,也就是(11111111 - 一個數的補碼)=這個數的反碼,也就是(11111111 - 一個數的補碼)=把這個數按位取反,到現在,你應該你已經很清楚他是怎麽來的了。

  那麽我們現在就可以把公式寫成這樣,(11111111 - 一個數的補碼)+00000001=它相反數的補碼,現在我們知道了(11111111 - 一個數的補碼)=把這個數按位取反,然後把公式裏的(11111111 - 一個數的補碼)換成 “按位取反”,也就是 (按位取反)+000000001=它相反數的補碼,現在,按位取反,再加一,就終於出來了,這就是各大書籍資料所講的,補碼=按位取反+1..。好了,真相大白

轉載於

http://blog.csdn.net/wenxinwukui234/article/details/42119265

補碼(為什麽按位取反再加一):告訴你一個其實很簡單的問題