計算機中的數存放在寄存器中,一般將寄存器的位數稱爲機器字長, 你們說的無符號數其實就是不區分正負號的數,換句話說,就是沒負數,全是正數,你們知道,計算機中的數是以0-1存儲的, 假如咱們的寄存器16位, 無符號數表示的範圍就是0~65535 (2^64=65536), 有符號就是分正負數,總數65536就被分紅兩半,一半正數,通常負數,範圍就是 -32768~32767框架
有符號數,就是正負數同時存在, 人們當然能區分開整正負數,計算機怎麼區分呢?學習
前面說了,計算機只認識01這樣的數,因而人們規定 0表示正數, 1表示負數, 因而這樣符號就被數字化了, 而且規定將其放在真實值前面, 因而有符號數就誕生了編碼
如上圖,按照計算機存數數據的特性將符號數字化, 數字化後的編碼方式獲得的結果稱爲機器數, 將帶有+-符號的數字稱爲真值設計
既然如今將有符號數數字化後,新的問題來了,當這些機器數之間須要進行運算時, 符號位怎麼辦? 符號位可否參加機器數之間的運算呢? 若是說,須要參加運算又須要哪些處理才能消除符號位對計算結果的影響呢? 這一連串問題就引出了符號位和數值位所構成的編碼: 原碼 , 補碼 , 反碼 , 移碼 3d
其實在學習的過程當中該一直問本身,本身在幹什麼??? 就好比如今,我在前面大概說了說計算機是如何表示數字的,因而認識了機器碼,機器碼之間須要進行運算於爲了設計出使機器碼運算的方式,人們對機器碼進行不一樣的變形編碼,獲得了,原碼 , 補碼, 反碼 , 移碼等, 下面看一下這幾種編碼的由來,以及他們對實現機器碼的可計算的貢獻code
原碼是機器碼最簡單的一種變形,一樣的它的符號位0表示正數,1表示負數。 數值位就是真值的絕對值blog
人們爲了書寫方便已經區分小數和整數,在符號位和數值位之間使用逗號分隔數學
舉個例子:table
x= +1110, 那麼它的原碼就是 0,1110 x= -1110, 原碼=1,1110
舉個例子class
x= 0.1101 , 那麼它的原碼就是 0.1101 x= -0.1101, 原碼=1 - (-0.1101) = 1.1101
看上面的原碼計算方式,顯然機器碼很容易就轉成原碼,可是想一想若是用原碼進行數值運算的話就會帶來不少麻煩,咱們得先判斷兩個機器數絕對值的大小而後用大的減去小的,最終的符號再按照絕對值大的算, 並且咱們須要設計兩套運算流程,一套給加法用,一套給減法用, 可是前輩們很智慧,由於人們找到了一種方式,找到了一個正數去替換原來減數位置的負數,相似像下面這樣,實現了在計算機中僅僅設計一套加法器就實現加減法的運算
5-3=2 5+(-3)=2
上述方法的實現就依賴於下面的補碼
補碼的概念和補數的概念很像, 好比如今時鐘六點了,咱們想讓它指向三點,因而咱們能夠往回轉3(6-3=3)圈時針能回退到3點,也能夠往前轉9圈(6+9=15),能夠前進到三點, 對時鐘來講往順時針仍是逆時針的過程不同,可是對咱們來講結果是同樣的,都是三點了
這個過程就相似於,找到一個正數,讓這個正數代替負數去參加運算,使用加法運算器也能獲得正確的結果
時鐘旋轉一圈12小時,在這12小時中是不被顯示且自動丟失的,也就是說 15-3=3 點, 因而咱們能夠說,其實對時鐘來講, -3 +9 的做用實際上是一致的,結果都是三點, 在數學上咱們將12稱爲模 ,寫成mod 12 , 咱們管9 稱爲是 -3以12爲模的補數
因而咱們得知,只要咱們肯定了模,咱們就能求出這個數對這個模的地位相同的補數,或者說當咱們想將已知的負數轉換成能夠替換他的正數的話,藉助模就能夠完成
如何利用模求補數呢?
如何進行求模示例:
-3 全等於 +7 (mod10) +7 全等於 +7 (mod10) -3 全等於 +97 (mod100) -1011 全等於 +0101 (mod2^4) 2^4=1 0 0 0 0 - 1 0 1 1 --------------- 0 1 0 1 +0101 全等於 +0101 (mod2^4) 小數的mod = 2 +0.1001 全等於 +0.1001 (mod2) -0.1001 全等於 +1.0111 (mod2) 1 0.0 0 0 0 - 0.1 0 0 1 -------------- 1.0 1 1 1
求補碼的公式
求負數補數的示例
其實你們能夠看一下,對負數的公式來講,公式中的n就是負數的位數, -1101 一共四位, n=4, 可是取的是n+1位, 換句話說是用一個比原負數多兩位的數加上這個負數, 多出來一個符號位, 最後的結果中別忘了用 逗號分隔符號位和數值位, 固然這是爲了方便咱們本身看,讓人們一眼看去知道最開始的1是個符號位,後面的數纔是 想求的補數結果
小數求補碼的公式
舉個例子: 求 -0.0110 的補碼
此外, +0 -0的補碼都是 0
從上面的討論咱們知道,之因此想引入補碼是爲了消除減法運算,即將一個負數轉換成它的正數補碼,可是根據補碼的定義,你們能夠看到上面的兩個例子,在產生補碼的過程當中又出現了減法運算,怎麼辦呢?
因而咱們這樣求補碼: 先求原碼, 而後變換這個原碼獲得補碼, 怎麼變換呢? 就是將除了 符號位的原碼其它爲取反 以後再加1
舉個例子: 上面的就用 -1101 來講, 以下:
因而看到這裏咱們完全知道了,只爲計算機設計一個加法器是徹底ok的,下文會介紹如何運算
經過上面的運算咱們知道下面的運算規則
原碼(符號位,數值位) => 除符號位外其餘位取反 = 反碼 反碼+1 = 補碼 補碼-1 = 反碼
由此可知,其實這個反碼就是原碼和補碼雙方轉換時的中間狀態
真值轉換成補碼後,因爲符號位和數值位是一塊兒進行編碼的,所以人們很難分清補碼之間的大小
就像下面這樣
十進制的21 對應二進制爲+10101 補碼爲 0,10101 十進制的-21 對應二進制爲-10101 補碼爲 1,01011 十進制的31 對應二進制爲 +11111 補碼爲 0,11111 十進制的-31 對應二進制爲-11111 補碼爲 1,00001
直觀上看他們的大小是 101011>010101 100001>011111 而實際上偏偏相反
因而咱們這樣, 在每個真值的基礎上加上一個2^n , 狀況就發生了變化
+10101 加上2^5 得 110101 -10101 加上2^5 得 001011 +11111 加上2^5 得 111111 -11111 加上2^5 得 000001
這樣的話不須要藉助補碼,六位代碼自己就能看到出真值的大小
更進一步,經過觀察能夠發現,其實一個數的補碼和移碼之間就差一個符號位,換句話說,若是咱們將補碼的符號位從0換爲1,或者從1換成0獲得的就是它的移碼, 在這基礎上比較大小獲得的結果是準確的
此外正負零的移碼的同樣的
計算機中的機器數的字長每每是固定的,當機器數左移n位或者是又移n位時,勢必會卻是另一邊出現空位,那麼在出現空位的位置究竟是補充1仍是填充0呢? 這取決於機器數是有符號仍是無符號,其中有符號的機器數採起的位移稱爲算數位移,無符號的惟一稱爲邏輯位移
真值 | 碼制 | 補填代碼 |
---|---|---|
正數 | 原碼,補碼,反碼 | 0 |
負數 | 原碼 | 0 |
負數 | 原碼 | 左移添0 |
負數 | 補碼 | 右移添1 |
負數 | 反碼 | 1 |
不管是正數仍是負數,移位後的符號位都是不變的
舉幾個例子
機器數 十進制 移位前 : 0,0011010 +26 左移1位: 0,0110100 +52 右移1位: 0,0001101 +13
左移一位,除符號位外原來的最高位被移走了,右邊空出的1位用0補全,可是高位丟失了其實獲得的就是錯誤的結果,可是這個錯誤的結果剛好是原值的2倍,並且惟一運算速度還快,所以不少框架的底層都青睞使用這個位移運算的特性
每次右移時,最右邊的數就會丟失,精度收到影響
左移一位至關於乘以2,右移1位至關於除以2
邏輯左移,高位丟失,低位填0, 邏輯右移,低位丟失,高位補0
回到一開始話題,計算機的運算方法,前面經過補碼的介紹咱們知道了只設計一套加法器實際上是可行的,下面具體看一下是如何進行運算的
即 A-B = A + (-B)
補碼的加法公式
整數: [A]補 + [B]補 = [A+B]補 (mod 2^n+1) 小數: [A]補 + [B]補 = [A+B]補 (mod 2)
對於減法來講
整數: [A-B]補 = [A]+[-B]補 (mod 2^n+1) 小數: [A-B]補 = [A]+[-B]補 (mod 2)
最後看一個例子: 看看計算機如何將減法轉換成加法並攜帶符號位運行得出正確結果
假設機器8位(含一位符號位),若A=+15 B=+24, 讓咱們求 [A-B]補 ,並還原真值
A=+15 = +0001111 (算上+號一共八位) b=+24 = +0011000 (算上+號一共八位) A和B都是整數,因此他們的補碼就是原碼自己: [A]補 = 0,0001111 [B]補 = 0,0011000 [-B]原碼 = 1,0011000 [-B]反碼 = 1,1100111 ( 除符號位取反獲得反碼:) [-B]補 = 1,1101000 (由反碼+1獲得) [A-B]補 = [A]補 + [-B]補 = 0,0001111 + 1,1101000 = 1,1110111 那麼 A-B = 啥呢? 反着換回去 1,1110111 1,1110110 (末位減1再取反) 1,0001001 = -0001001 = -9