原碼、反碼、補碼詳解

      網友投稿 1395 2025-03-31

      一 . 機器數和真值

      在學習原碼 , 反碼和補碼之前 , 需要先了解機器數和真值的概念 .

      1 、機器數

      一個數在計算機中的二進制表示形式 ,? 叫做這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號 , 正數為 0, 負數為 1.

      比如,十進制中的數 +3 ,計算機字長為 8 位,轉換成二進制就是 00000011 。如果是 -3 ,就是 10000011 。

      那么,這里的 00000011 和 10000011 就是機器數。

      2 、真值

      因為第一位是符號位,所以機器數的形式值就不等于真正的數值。例如上面的有符號數 10000011 ,其最高位 1 代表負,其真正數值是 -3 而不是形式值 131 ( 10000011 轉換成十進制等于 131 )。所以,為區別起見,將帶符號位的機器數對應的真正數值稱為機器數的真值。

      例: 0000 0001 的真值 = +000 0001 = +1 , 1000 0001 的真值 = –000 0001 = –1

      二 . 原碼 , 反碼 , 補碼的基礎概念和計算方法 .

      在探求為何機器要使用補碼之前 , 讓我們先了解原碼 , 反碼和補碼的概念 . 對于一個數 , 計算機要使用一定的編碼方式進行存儲 . 原碼 , 反碼 , 補碼是機器存儲一個具體數字的編碼方式 .

      1. 原碼

      原碼就是符號位加上真值的絕對值 , 即用第一位表示符號 , 其余位表示值 . 比如如果是 8 位二進制 :

      [+1] 原 ?= 0000 0001

      [-1] 原 ?= 1000 0001

      第一位是符號位 . 因為第一位是符號位 , 所以 8 位二進制數的取值范圍就是 :

      [1111 1111 , 0111 1111]

      [-127 , 127]

      原碼是人腦最容易理解和計算的表示方式 .

      2. 反碼

      反碼的表示方法是 :

      正數的反碼是其本身

      負數的反碼是在其原碼的基礎上 , 符號位不變,其余各個位取反 .

      [+1] = [00000001] 原 ?= [00000001] 反

      [-1] = [10000001] 原 ?= [11111110] 反

      可見如果一個反碼表示的是負數 , 人腦無法直觀的看出來它的數值 . 通常要將其轉換成原碼再計算 .

      3. 補碼

      補碼的表示方法是 :

      正數的補碼就是其本身

      負數的補碼是在其原碼的基礎上 , 符號位不變 , 其余各位取反 , 最后 +1. ( 即在反碼的基礎上 +1)

      [+1] = [00000001] 原 ?= [00000001] 反 ?= [00000001] 補

      [-1] = [10000001] 原 ?= [11111110] 反 ?= [11111111] 補

      對于負數 , 補碼表示方式也是人腦無法直觀看出其數值的 . 通常也需要轉換成原碼在計算其數值 .

      原碼、反碼、補碼詳解

      三 . 為何要使用原碼 , 反碼和補碼

      在開始深入學習前 , 我的學習建議是先 " 死記硬背 " 上面的原碼 , 反碼和補碼的表示方式以及計算方法 .

      現在我們知道了計算機可以有三種編碼方式表示一個數 . 對于正數因為三種編碼方式的結果都相同 :

      [+1] = [00000001] 原 ?= [00000001] 反 ?= [00000001] 補

      所以不需要過多解釋 . 但是對于負數 :

      [-1] = [10000001] 原 ?= [11111110] 反 ?= [11111111] 補

      可見原碼 , 反碼和補碼是完全不同的 . 既然原碼才是被人腦直接識別并用于計算表示方式 , 為何還會有反碼和補碼呢 ?

      首先 , 因為人腦可以知道第一位是符號位 , 在計算的時候我們會根據符號位 , 選擇對真值區域的加減 . ( 真值的概念在本文最開頭 ). 但是對于計算機 , 加減乘數已經是最基礎的運算 , 要設計的盡量簡單 . 計算機辨別 " 符號位 " 顯然會讓計算機的基礎電路設計變得十分復雜 ! 于是人們想出了將符號位也參與運算的方法 . 我們知道 , 根據運算法則減去一個正數等于加上一個負數 , 即 : 1-1 = 1 + (-1) = 0 , 所以機器可以只有加法而沒有減法 , 這樣計算機運算的設計就更簡單了 .

      于是人們開始探索 將符號位參與運算 , 并且只保留加法的方法 . 首先來看原碼 :

      計算十進制的表達式 : 1-1=0

      1 - 1 = 1 + (-1) = [00000001] 原 ?+ [10000001] 原 ?= [10000010] 原 ?= -2

      如果用原碼表示 , 讓符號位也參與計算 , 顯然對于減法來說 , 結果是不正確的 . 這也就是為何計算機內部不使用原碼表示一個數 .

      為了解決原碼做減法的問題 , 出現了反碼 :

      計算十進制的表達式 : 1-1=0

      1 - 1 = 1 + (-1) = [0000 0001] 原 ?+ [1000 0001] 原 = [0000 0001] 反 ?+ [1111 1110] 反 ?= [1111 1111] 反 ?= [1000 0000] 原 ?= -0

      發現用反碼計算減法 , 結果的真值部分是正確的 . 而唯一的問題其實就出現在 "0" 這個特殊的數值上 . 雖然人們理解上 +0 和 -0 是一樣的 , 但是 0 帶符號是沒有任何意義的 . 而且會有 [0000 0000] 原 和 [1000 0000] 原 兩個編碼表示 0.

      于是補碼的出現 , 解決了 0 的符號以及兩個編碼的問題 :

      1-1 = 1 + (-1) = [0000 0001] 原 ?+ [1000 0001] 原 ?= [0000 0001] 補 ?+ [1111 1111] 補 ?= [0000 0000] 補 =[0000 0000] 原

      這樣 0 用 [0000 0000] 表示 , 而以前出現問題的 -0 則不存在了 . 而且可以用 [1000 0000] 表示 -128:

      (-1) + (-127) = [1000 0001] 原 ?+ [1111 1111] 原 ?= [1111 1111] 補 ?+ [1000 0001] 補 ?= [1000 0000] 補

      -1-127 的結果應該是 -128, 在用補碼運算的結果中 , [1000 0000] 補 ? 就是 -128. 但是注意因為實際上是使用以前的 -0 的補碼來表示 -128, 所以 -128 并沒有原碼和反碼表示 .( 對 -128 的補碼表示 [1000 0000] 補算出來的原碼是 [0000 0000] 原 , 這是不正確的 )

      使用補碼 , 不僅僅修復了 0 的符號以及存在兩個編碼的問題 , 而且還能夠多表示一個最低數 . 這就是為什么 8 位二進制 , 使用原碼或反碼表示的范圍為 [-127, +127], 而使用補碼表示的范圍為 [-128, 127].

      因為機器使用補碼 , 所以對于編程中常用到的 32 位 int 類型 , 可以表示范圍是 : [-2 31 , 2 31 -1] 因為第一位表示的是符號位 . 而使用補碼表示時又可以多保存一個最小值 .

      四 原碼 , 反碼 , 補碼 再深入

      計算機巧妙地把符號位參與運算 , 并且將減法變成了加法 , 背后蘊含了怎樣的數學原理呢 ?

      將鐘表想象成是一個 1 位的 12 進制數 . 如果當前時間是 6 點 , 我希望將時間設置成 4 點 , 需要怎么做呢 ? 我們可以 :

      1. 往回撥 2 個小時 : 6 - 2 = 4

      2. 往前撥 10 個小時 : (6 + 10) mod 12 = 4

      3. 往前撥 10+12=22 個小時 : (6+22) mod 12 =4

      2,3 方法中的 mod 是指取模操作 , 16 mod 12 =4 即用 16 除以 12 后的余數是 4.

      所以鐘表往回撥 ( 減法 ) 的結果可以用往前撥 ( 加法 ) 替代 !

      現在的焦點就落在了如何用一個正數 , 來替代一個負數 . 上面的例子我們能感覺出來一些端倪 , 發現一些規律 . 但是數學是嚴謹的 . 不能靠感覺 .

      首先介紹一個數學中相關的概念 : 同余

      同余的概念

      兩個整數 a , b ,若它們除以整數 m 所得的余數相等,則稱 a , b 對于模 m 同余

      記作 a ≡ b (mod m)

      讀作 a 與 b 關于模 m 同余。

      舉例說明 :

      4 mod 12 = 4

      16 mod 12 = 4

      28 mod 12 = 4

      所以 4, 16, 28 關于模 12 同余 .

      負數取模

      正數進行 mod 運算是很簡單的 . 但是負數呢 ?

      下面是關于 mod 運算的數學定義 :

      上面是截圖 , " 取下界 " 符號找不到如何輸入 (word 中粘貼過來后亂碼 ). 下面是使用 "L" 和 "J" 替換上圖的 " 取下界 " 符號 :

      x mod y = x - y L x / y J

      上面公式的意思是 :

      x mod y 等于 x 減去 y 乘上 x 與 y 的商的下界 .

      以 -3 mod 2 舉例 :

      -3 mod 2

      = -3 - 2xL -3/2 J

      = -3 - 2xL-1.5J

      = -3 - 2x(-2)

      = -3 + 4 = 1

      所以 :

      (-2) mod 12 = 12-2=10

      (-4) mod 12 = 12-4 = 8

      (-5) mod 12 = 12 - 5 = 7

      開始證明

      再回到時鐘的問題上 :

      回撥 2 小時 = 前撥 10 小時

      回撥 4 小時 = 前撥 8 小時

      回撥 5 小時 = 前撥 7 小時

      注意 , 這里發現的規律 !

      結合上面學到的同余的概念 . 實際上 :

      (-2) mod 12 = 10

      10 mod 12 = 10

      -2 與 10 是同余的 .

      (-4) mod 12 = 8

      8 mod 12 = 8

      -4 與 8 是同余的 .

      距離成功越來越近了 . 要實現用正數替代負數 , 只需要運用同余數的兩個定理 :

      反身性 :

      a ≡ a (mod m)

      這個定理是很顯而易見的 .

      線性運算定理 :

      如果 a ≡ b (mod m) , c ≡ d (mod m) 那么 :

      (1)a ± c ≡ b ± d (mod m)

      (2)a * c ≡ b * d (mod m)

      如果想看這個定理的證明 , 請看 : http://baike.baidu.com/view/79282.htm

      所以 :

      7 ≡ 7 (mod 12)

      (-2) ≡ 10 (mod 12)

      7 -2 ≡ 7 + 10 (mod 12)

      現在我們為一個負數 , 找到了它的正數同余數 . 但是并不是 7-2 = 7+10, 而是 7 -2 ≡ 7 + 10 (mod 12) , 即計算結果的余數相等 .

      接下來回到二進制的問題上 , 看一下 : 2-1=1 的問題 .

      2-1=2+(-1) = [0000 0010] 原 ?+ [1000 0001] 原 = [0000 0010] 反 ?+ [1111 1110] 反

      先到這一步 , -1 的反碼表示是 1111 1110. 如果這里將 [1111 1110] 認為是原碼 , 則 [1111 1110] 原 = -126, 這里將符號位除去 , 即認為是 126.

      發現有如下規律 :

      (-1) mod 127 = 126

      126 mod 127 = 126

      即 :

      (-1) ≡ 126 (mod 127)

      2-1 ≡ 2+126 (mod 127)

      2-1 與 2+126 的余數結果是相同的 ! 而這個余數 , 正式我們的期望的計算結果 : 2-1=1

      所以說一個數的反碼 , 實際上是這個數對于一個膜的同余數 . 而這個膜并不是我們的二進制 , 而是所能表示的最大值 ! 這就和鐘表一樣 , 轉了一圈后總能找到在可表示范圍內的一個正確的數值 !

      而 2+126 很顯然相當于鐘表轉過了一輪 , 而因為符號位是參與計算的 , 正好和溢出的最高位形成正確的運算結果 .

      既然反碼可以將減法變成加法 , 那么現在計算機使用的補碼呢 ? 為什么在反碼的基礎上加 1, 還能得到正確的結果 ?

      2-1=2+(-1) = [0000 0010] 原 ?+ [1000 0001] 原 ?= [0000 0010] 補 ?+ [1111 1111] 補

      如果把 [1111 1111] 當成原碼 , 去除符號位 , 則 :

      [0111 1111] 原 ?= 127

      其實 , 在反碼的基礎上 +1, 只是相當于增加了膜的值 :

      (-1) mod 128 = 127

      127 mod 128 = 127

      2-1 ≡ 2+127 (mod 128)

      此時 , 表盤相當于每 128 個刻度轉一輪 . 所以用補碼表示的運算結果最小值和最大值應該是 [-128, 128].

      但是由于 0 的特殊情況 , 沒有辦法表示 128, 所以補碼的取值范圍是 [-128, 127]

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:OKR工作法(二)之如何制定OKR(okr工作法舉例)
      下一篇:excel日期yy-mm-dd如何變成yy/mm/dd
      相關文章
      亚洲免费视频网站| 亚洲中文字幕无码爆乳av中文 | 亚洲国产综合精品一区在线播放| 亚洲欧美日韩一区二区三区在线 | 亚洲精品无码久久毛片| 亚洲乱妇熟女爽到高潮的片| 亚洲男人天堂2022| 亚洲熟妇无码八V在线播放| 色噜噜亚洲男人的天堂| 亚洲一区二区三区免费观看| 亚洲黄色中文字幕| 亚洲欧洲视频在线观看| 亚洲国产精品专区| 亚洲一区在线免费观看| 久久精品国产99国产精品亚洲| 亚洲专区一路线二| 亚洲综合欧美色五月俺也去| 亚洲私人无码综合久久网| 亚洲AV噜噜一区二区三区| 亚洲欧美在线x视频| 亚洲第一区在线观看| 亚洲无码黄色网址| 亚洲中文字幕第一页在线| 亚洲精品无码av人在线观看| 亚洲AV日韩AV永久无码下载| 亚洲视频在线观看地址| 亚洲av一本岛在线播放| 亚洲成a人片在线不卡一二三区| 亚洲av无码av在线播放| 亚洲国产精品成人网址天堂| 在线观看国产区亚洲一区成人| 国产亚洲精品a在线观看app| 亚洲小视频在线观看| 亚洲冬月枫中文字幕在线看| 中文字幕乱码亚洲无线三区 | 亚洲国产综合专区电影在线| 亚洲国产高清美女在线观看| 亚洲色成人WWW永久在线观看| 一级毛片直播亚洲| 亚洲精品无码Av人在线观看国产| 亚洲产国偷V产偷V自拍色戒 |