【計算機原理】求一個機器數的反碼

 

首先,解釋一下反碼的概念:反碼是數值存儲的一種,簡單點說就是在計算機內定點數的表示法之一,除了反碼,常用的還有原碼,補碼,移碼等。暗戳戳地說一下,反碼其實是用得很少的~

但是!反碼用處還是挺大的,比如說作爲機器數運算的中間數,雖然用補碼更多一些吧,再比如說系統環境設置,像linux平臺的目錄和文件的默認權限的設置umask就是的使用反碼原理。

總之,存在即是合理,反碼就是這麼真實存在的一種編碼方式。

其次,套用一下教科書上的東西:正數的反碼是其本身,負數的反碼是在其原碼的基礎上, 符號位不變,其餘各個位取反。

老陌在此用自己的理解解釋一下,就是說求一個數的反碼主要分成兩個方向:正數和負數。其中最簡單的就是正數了,只要原模原樣照搬就可以了;然後是夾在正數和負數中間的0,因爲在計算機中0的原碼反碼是分成+0和-0的,所以這個特例還真要分類討論;最後是負數,整數的做法也就是按位取反,符號位不變,小數的話印象中是有定點小數和浮點小數之分,我記得以前計算浮點小數還要先把小數轉換成整數,然後算完了再把小數點向前移動多少位,最後才能求出實際的數值。

綜上,在老陌的印象中求反碼的難易等級是這樣的:正整數(易)--->正小數--->零--->負整數--->負小數(難)

接下來老陌將以8位的二進制機器數爲例,其中首位爲符號位(0爲正,1爲負),所以決定真值範圍的也是後面的7位。

當然,在老陌的印象中是學習過的雙符號位的表示方法的,如果兩個符號位不同就表示產生溢出。其中最高位(第一個符號位)表示正確的符號,01表示正溢出,10表示負溢出。相較於我們最開始學的單符號位,雙符號位是可以參與運算的,所以更接近於我們小時候養成的數學運算的習慣。但是,這種表示方法(變形編碼)一般是用在電子電路的設計裏面的,所以在此老陌就不討論了。

X=7,[7]真=[0000 0111]原=[0000 0111]反

X=-7,[-7]真=[1000 0111]原=[1111 1000]反

當然,還有一個特例:+0和-0。

X=0,[+0]真=[0000 0000]原=[1111 1111]反

X=0,[-0]真=[1000 0000]原=[0111 1111]反

接下來再來看一下小數的例子,其實用書上的概念來做還是挺簡單的。

X=0.625,[+0.625]真=[0.10100000]原=[0.10100000]反

X=-0.625,[-0.625]真=[1.10100000]原=[1.01011111]反

p.s.不過在這裏有一點需要特別注意一下,不是所有的小數都可以轉化成二進制小數的,比如說0.73D=?B我相信算出來的二進制小數肯定是無限接近於十進制的0.73吧?   

綜上,求解一個機器數的反碼其實挺簡單的。

 

但是,忽然有這麼一天,老哥發來了一張圖片,然後“賊兮兮”地問我看得懂不?

老陌定睛一看:範圍寫得這麼“裝逼”?而且前面的公式裏怎麼會是加法?不會越界嗎?

反碼公式

接下來老陌就帶着疑惑去看了一下網上的資料,然後,我感覺老哥給我打開了一個新世界!有句話怎麼說的來着,“計算機的世界有無數道門窗,無論我們打開哪一道,都能收穫無窮盡的風景!”真的,這裏邊的風景很好,老陌忍不住想要記錄下來!

 

首先糾正一點(其實看得懂的人也不需要糾正什麼),上面的兩個取值範圍應該是這樣的:

整數[x]反 = (2^ n+1 -1)+x       0>=x>-2^n * (mod (2^ n+1 -1)),

同理,小數[x]反 = (2 - 2^ -n)+x       0>=x>-1 * (mod (2 - 2^ -n+)),

這裏想要強調的是最後面的取模並非只是對第一個被減數進行了操作,然後取模和前面的數字求出來的乘積纔是取值範圍中的臨界點。

接下來再來解釋一下爲什麼會是 (2^ n+1 -1) 和 (2 - 2^ -n) 以及最後爲什麼會是+x。

先來看負整數:

還是以X=-7爲例,由於老哥給的公式是計算(n+1)位二進制數的,所以,這裏的n=7,根據公式可得:

[-7]反 = [2^8-1+(-7)]

在這裏(2^8-1)D 可以理解成1 0000 0000 B - 1 B ,也就是八位的最大二進制數 1111 1111

那麼,這個公式是不是就可以這麼解釋:一個數的反碼等於最大的那個數加上它本身?也就相當於是一個時鐘裏的指針轉了一圈再次回到它本來的位置。

思及此處,老陌突然感覺這個理論和以前學過的同餘定理的概念非常相似!簡單來說就是:

許多的數被一個數d去除,有相同的餘數。d數學上的稱謂爲模。如a=6,b=1,d=5,則我們說a和b是模d同餘的。因爲他們都有相同的餘數1。

數學上的記法爲:

a≡ b(mod d)

然後利用常見的結合律,交換律,傳遞律等等可以知道:

如果a≡x(mod d),b≡m(mod d),則

4)a+b≡x+m (mod d)

5)a-b≡x-m (mod d)

6)a*b≡x*m (mod d )

接下來讓我們一起來驗證一下:[-7]反= [1111 1111B] -[0000 0111B]=[1111 1000B] 結果和我們剛纔算出來的反碼是一樣的!

接下來再來看一下負小數:

同樣以X=-0.625爲例,此時n=7,根據公式可得:

[-0.625]反=[2-2^(-7)+(-0.625)]

這裏的 2-2^(-7) 可以這麼提取公因式 2^(-7) *(2^8 - 1)

根據上面的例子我們可以知道(2^8-1)D 就是八位的最大二進制數 1111 1111 ,然後把它的小數點往前移七位 可以得到:1.111 1111 ,接着讓我們一起來見證一個奇蹟的時刻:

[-0.625]反=[1.111111-0.101B]=[1.010111B]

p.s.因爲這裏的小數點後面只有6位,所以爲了規範我們需要自動補全末尾的兩位,在原碼裏補的是0,反碼對應的就是1,所以最後得出的答案是[-0.625]反=[1.0101 1111B]

 

在解題的過程中老陌還發現了一個“現象”:公式裏的 +x 由於x是負數,所以後來都變成了 - |x| ,而實際運算過程中並不考慮前面第一個數字是否是符號位。這應該算是一個比較容易混淆的地方~

 

參考資料:

原反補碼

反碼

計算機中的真值和機器數

8位原碼反碼補碼錶

同餘定理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章