本章的思維導圖:
前提知識
要了解什麼是進制編碼,原碼,反碼,補碼,那你就必須要了解計算機的發展史,以及計算機存儲信息的方式,
如果是有計算機基礎的同學,或者對這部分知識已經有所瞭解,可以跳過此部分
計算機發展史
計算機(Computer)俗稱電腦,是現代一種用於高速計算的電子計算機器,可以進行數值計算,又可以進行邏輯計算,還具有存儲記憶功能。是能夠按照程序運行,自動、高速處理海量數據的現代化智能電子設備。
計算機的發展經歷了四代的演變,從1946年第一臺電子計算機的誕生,到目前分別經歷了
- 第1代:電子管數字機(1946—1958年)
- 第2代:晶體管數字機(1958—1964年)
- 第3代:集成電路數字機(1964—1970年)
- 第4代:大規模集成電路機(1970年到至今)
我們目前主要使用的計算機都是大規模集成電路機,是採用大規模和超大規模的集成電路作爲邏輯元件的。
集成電路(Integrated Circuit)
集成電路,按其功能、結構的不同,可以分爲三大類:
- 模擬集成電路
- 數字集成電路
- 數/模混合集成電路
集成電路(Integrated Circuit)是一種微型電子器件或部件。採用一定的工藝,把一個電路中所需的晶體管、電阻、電容和電感等元件及佈線互連一起,製作在一小塊或幾小塊半導體晶片或介質基片上,然後封裝在一個管殼內,成爲具有所需電路功能的微型結構。
模擬集成電路又稱線性電路,用來產生、放大和處理各種模擬信號(指幅度隨時間變化的信號。例如半導體收音機的音頻信號、正弦波、三角波等),其輸入信號和輸出信號成比例關係。
1、模擬信號 : Analog Signal
2、數字信號 Digital Signal
數字集成電路用來產生、放大和處理各種數字信號(指在時間上和幅度上離散取值的信號。例如3G手機、數碼相機、電腦CPU、數字電視的邏輯控制和重放的音頻信號和視頻信號)。
也就是工科生經常聽到以及學習的 模電 與 數電
而我們的計算機主要是採用數字集成電路搭建的。
數字集成電路
用數字信號完成對數字量進行算術運算和邏輯運算的電路稱爲數字電路,或數字系統。由於它具有邏輯運算和邏輯處理功能,所以又稱數字邏輯電路。
而數字電子技術中,我們使用低、高電平表示0、1兩種邏輯狀態 ( 也就是分別代表邏輯上的“真”與“假” 或 二進制當中的“1”和“0”) 從而實現邏輯運算。
常見的邏輯門包括“與”門,“或”門,“非”門,“異或”等等。邏輯門可以組合使用實現更爲複雜的邏輯運算。
數字電路具有以下特點:
- 1、同時具有算術運算和邏輯運算功能
數字電路是以二進制邏輯代數爲數學基礎,使用二進制數字信號,既能進行算術運算又能方便地進行邏輯運算(與、或、非、判斷、比較、處理等),因此極其適合於運算、比較、存儲、傳輸、控制、決策等應用。 - 2、實現簡單,系統可靠
以二進制作爲基礎的數字邏輯電路,可靠性較強。電源電壓大小的波動對其沒有影響,溫度和工藝偏差對其工作的可靠性影響也比模擬電路小得多。 - 3、集成度高,功能實現容易
集成度高,體積小,功耗低是數字電路突出的優點之一。電路的設計、維修、維護靈活方便,隨着集成電路技術的高速發展,數字邏輯電路的集成度越來越高。
由於其具有以上特點,所以,數字電路與數字電子技術廣 - 4、具可編程性,可實現硬件設計軟件化
- 5、高速度 低功耗 加密性好
泛的應用於電視、雷達、通信、電子計算機、自動控制、航天等科學技術領域
此部分我們將在第二節中介紹
0 1思維
我們知道計算機的本質是數字集成電路,也就是晶體管, 而晶體管只能表示 高電平 真 低電平 假 兩種狀態
我們所看到的任何東西,計算機在真正運行時都要被轉換成**二進制機器碼(0/1)**才能夠識別和運算
就好比老師讓你回收到的時候會說 :同學們,懂得扣個1,不懂得扣個0
那這個1 和0 就是對數據的存儲
二進制是計算機運行的基礎
也就是: 計算機是用 0 1來存儲數據的
、
1Bit
1Bit 也就是一個字節 是八位 也就是取值範圍爲 0000 0000~1111 1111
機器碼
一個數在計算機中的二進制表示形式,叫做這個數的機器數。機器數是帶符號的,在計算機用機器數的最高位存放符號,正數爲0,負數爲1。
比如,十進制中的數 +3 ,計算機字長爲8位,轉換成二進制就是0000 0011。如果是 -3 ,就是 100 00011 。
那麼,這裏的 0000 0011 和 1000 0011 就是機器數。
加法器
計算機裏面,只有加法器,沒有減法器,也就是沒有減法運算,所有的減法運算,都必須用加法進行。
即:減去某個數字(也就是相當於加上某個負數)的運算,都應該研究如何用加法來完成。
二進制與十進制之間的轉換
二進制與十進制相信各位都有所瞭解了,所以這裏我們只介紹其轉換,而不介紹其概念,
1.十進制轉二進制
方法爲:十進制數除2取餘法,即十進制數除2,餘數爲權位上的數,得到的商值繼續除,直到商爲0爲止。
2**.二進制轉十進制**
方法爲:把二進制數按權展開、相加即得十進制數。
第幾位二進制數就是二的幾次方
BCD編碼
BCD碼也稱二進碼十進數,BCD碼可分爲有權碼和無權碼兩類。常見的有權BCD碼有8421碼、2421碼、5421碼,無權BCD碼有餘3碼、餘3循環碼、格雷碼。
8421BCD碼是最基本和最常用的BCD碼,它和四位自然二進制碼相似,它只選用了四位二進制碼中前10組代碼,即用0000···1001分別代表十進制數的0~9,餘下的六組代碼不用。
這裏我們介紹下 8421碼 5421 2421 和餘3碼
8421碼
8421 BCD碼是用四位二進制碼來表示一位十進制數。但是隻能表示0~9的十進制數。
如二進制的10010111BCD碼轉換成十進制是:97。
1001 0111
9 7
十進制24 轉換成8421碼是: 00100100
2 4
0010 0100
原碼,反碼,補碼
在瞭解了之前的知識以後,我們就要開始說 原碼,反碼,補碼 這三個碼了
原碼
我們知道,計算機就是個會處理0 1的機器,別說是正負號的漢字了,據算是+ - 字符也是束手無策。
那怎麼辦呢?
那你既然知道0 和1 是啥 那咱們就規定一下吧 0就代表正數,1代表負數。
原碼定義: 將二進制數據的第一位用來表示正負 其餘7位用來表示數值
[+1]原碼 = 0 000 0001
[-1]原碼 = 1 000 0001
第一位是符號位. 因爲第一位是符號位, 所以8位二進制數的取值範圍就是:
[1111 1111 , 0111 1111]==>[-127 , 127]
這樣只會加法運算的計算機就可以做加減運算了 ,但是呢,這樣子有個問題
我們希望 1-1 = 1 + (-1) = 0 ,
但計算機只能算出0001+1001=1010 (-2)
同時我們這裏還有兩個0 : +0 -0
於是呢,爲了解決“正負相加等於0”的問題 反碼 就出現了
反碼
反碼的表示方法是 :
- 正數的反碼是其本身
- 負數的反碼是在其原碼的基礎上, 符號位不變,其餘各個位取反.
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
這時我們發現 (+1)和(-1)相加,變成了0001+1101=1111,剛好反碼錶示方式中,1111象徵-0
唯一的問題其實就出現在"0"這個特殊的數值上. 雖然人們理解上+0和-0是一樣的, 但是0帶符號是沒有任何意義的. 而且會有[0000 0000]原和[1000 0000]原兩個編碼表示0.
我們希望只有一個0,所以發明了"補碼"
補碼
補碼的表示方法是:
- 正數的補碼就是其本身
- 負數的補碼是在其原碼的基礎上, 符號位不變, 其餘各位取反, 最後+1. (即在反碼的基礎上+1)
[+1] = [00000001]原 = [00000001]反 = [00000001]補
[-1] = [10000001]原 = [11111110]反 = [11111111]補
我們要處理"反碼"中的"-0",當1111 1111再補上一個1之後,變成了1 0000 0000,丟掉最高位就是0000 0000,剛好就是左邊正數的0,
雖然丟掉了 -0 但是我們得到了-8
這個時候
1-1 = 1 + (-1) = = [0000 0001]補 + [1111 1111]補 = [0000 0000]補=0
而且可以用[1000 0000]表示-128:
在用補碼運算的結果中, [1000 0000]補 就是-128. 但是注意因爲實際上是使用以前的-0的補碼來表示-128, 所以 -128並沒有原碼和反碼錶示 .(對-128的補碼錶示[1000 0000]補算出來的原碼是[0000 0000]原, 這是不正確的)
但是使用補碼的方式,不僅僅修復了0的符號以及存在兩個編碼的問題, 而且還能夠多表示一個最低數
對於8位二進制, 使用原碼或反碼錶示的範圍爲[-127, +127], 而使用補碼錶示的範圍爲[-128, 127].
同時要記住一點:
正數的 原碼,反碼,補碼 都是其本身
[+1] = [00000001]原 = [00000001]反 = [00000001]補
擴展討論:
針對有計算機編程基礎的同學:
我們再來討論一下
學習過C語音或者其他語言的同學知道 字符型變量 的取值範圍爲[-128~127]
也就是 signed char的取值範圍爲-128 ~ 127
unsigned char 的取值範圍爲 0~255
到此時是你應該能明白,爲什麼是這樣了
所有的C語言的書籍裏都會告訴你signed char的取值範圍爲-128 ~ 127,但是從來沒有人告訴你爲什麼會是這樣;
我們先來算算,有符號的char佔一個字節,最高位表示正負,其餘的七位表示數值,七位二進制可以表示128個數(2^7 = 128),即0~127;加上符號位後,就變成了-127 ~ -0,0 ~127,這時,就會出現‘-0’這樣一朵奇葩;
在學習了上面之後,你會瞭解到因爲補碼的存在,所以我們實際可以存儲-128 ~ 127 但是在上方我們有說到 -128的反碼和原碼嚴格來講是不存在的
我對網上關於-0和-128原碼相同的這種說法表示很無語;
我們知道,計算機是以補碼的形式存數據的;-0和-128在計算機中是怎樣存的?
[-0] = [10000000]原 = [1111 1111]反 =[1000 0000 0]補
[-128] = [1000 0000]補 =
-128 沒有反碼和原碼
但是,我們的char類型是8位,因爲存儲是補碼形式 所以便有了 -128 如果非要定義的話 可以吧-0的原碼
[10000000]原 定義成-128的原碼
終於可以不提‘-0’這個噁心的東西了,今後看到一個有符號的char,它的原碼用二進制表示爲1000 0000的時候,我們就把它當做-128就可以了(只是看做,-128的原碼可不是1000 0000);
下面,我們來看一下這個程序:
#include <stdio.h>
int main(){
char a = -129;
printf("%d\n",a);
return 0;
}
它會打印127,爲什麼?
-129 = -128 -1;因爲計算機只會算加法,所以轉換成
-128 + (-1)
-128 原碼: 1000 0000
反碼: 0111 1111
補碼: 1000 0000
-1 原碼: 1000 0001
反碼: 1111 1110
補碼: 1111 1111
-128 + (-1)
1 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1
---------------------------
1 0 1 1 1 1 1 1 1
餘出來的那個1 被捨棄 最後結果爲 0 1 1 1 1 1 1 1 (-127)
因爲a是一個char類型的,所以,會打印127, 由此我們可以推出在char的取值超出範圍時的一些特徵
這只是研究階段,但請不要這樣使用!