計算機原碼、反碼、補碼的理解


(一)預備知識

(1) 二進制、八進制、十進制、十六進制之間的相互轉換

一、 二進制與十進制之間的轉換

1、二進制轉十進制(不分整數和小數從最后一位算起,每一位上的數乘以2的幾次方,這個次數由這個數字所在的位置決定,從零位開始,然后相加)

例:01101011.001轉十進制

 

 

 然后:1+2+0+8+0+32+64+0=107.125
01101011=107

2、十進制轉二進制

整數:除2取余法是一個連續除2的過程,直到商出現0時位置,余數反向排列;
例:整數23轉二進制:

 

 

然后把余數反向排列:23=10111

小數:乘2取整法,即將小數部分乘以2,然后取整數部分,剩下的小數部分繼續乘以2,然后取整數部分,剩下的小數部分又乘以2,一直取到小數部分 為零為止。如果永遠不能為零,就同十進制數的四舍五入一樣,按照要求保留多少位小數時,就根據后面一位是0還是1,取舍,如果是零,舍掉,如果是1,向入一位。換句話說就是0舍1入。讀數要從前面的整數讀到后面的整數。

例:0.125轉二進制

0.125乘以2,得0.25,則整數部分為0,小數部分為0.25;
0.25乘以2,得0.5,則整數部分為0,小數部分為0.5;
0.5乘以2,得1.0,則整數部分為1,小數部分為0.0;
從第一位讀起,讀到最后一位,即為0.001。

23.125 轉二進制10111.001

二、二進制與八進制之間的轉換(基礎還是二進制和十進制之間的轉換)

取三合一法,即從二進制的小數點為分界點,向左(向右)每三位取成一位,接着將這三位二進制按權相加,得到的數就是一位八位二進制數,然后,按順序進行排列,小數點的位置不變,得到的數字就是我們所求的八進制數。如果向左(向右)取三位后,取到最高(最低)位時候,如果無法湊足三位,可以在小數點最左邊(最右邊),即整數的最高位(最低位)添0,湊足三位)這里的最高位,最低位和十進制的一樣,前面的是最高位,后面的是最低位。

三位二進制表示一位八進制, 因為三位二進制數最大(111)的十進制數也就是7,所以就保證每位數都是0-7之間的數

1、二進制轉八進制

例:1100100轉為八進制

1100100拆分成:001 100 100

 

 

 依次讀下來就是:144
1100100=144

2、八進制轉二進制

八進制數與二進制數對應關系如下:

 

 

 例:將八進制數653524轉換為二進制

110 101 011 101 010 100

三、二進制與十六進制之間的轉換(基礎還是二進制和十進制之間的轉換)

四位二進制表示一位十六進制, 因為四位二進制數最大(1111)也就是十進制的表示法15即十六進制的表示法F,所以就保證每位數都是0-F之間的數。

1、二進制轉十六進制

例:1100100 拆分 0110 0100
0110=6
0100=4
1100100=64

2、十六進制轉二進制

十六進制數與二進制數之間的對應關系:

 

 

 四、十進制與十六進制之間的轉換

其算法和二進制和十進制之間的算法一樣只是,由2變成了16

1、十進制轉十六進制
例:十進制數123 轉成十六進制
123除16商7余B

7除16商0余7
結果就是7B
2、十六進制轉十進制
例:十六進數 2AF5

 

 

 2AF5=10997

參考原文:https://www.php.cn/faq/422257.html

(2)原碼、反碼、補碼的由來

由計算機的硬件決定,任何存儲於計算機中的數據,其本質都是以二進制碼存儲。

根據馮~諾依曼提出的經典計算機體系結構框架。一台計算機由運算器,控制器,存儲器,輸入和輸出設備組成。其中運算器,只有加法運算器,沒有減法運算器(據說一開始是有的,后來由於減法器硬件開銷太大,被廢了 )

所以,計算機中的沒法直接做減法的,它的減法是通過加法來實現的。你也許會說,現實世界中所有的減法也可以當成加法的,減去一個數,可以看作加上這個數的相反數。當然沒錯,但是前提是要先有負數的概念。這就為什么不得不引入一個該死的符號位。

  1. 而且從硬件的角度上看,只有正數加負數才算減法。

  2. 正數與正數相加,負數與負數相加,其實都可以通過加法器直接相加。

 

 

(二)原碼、反碼、補碼的理解

(1)概念

1、機器數:

一個數在計算機中的表現形式叫做機器數,這個數有正負之分,在計算機中用一個數的最高位(符號位)用來表示它的正負,其中0表示正數,1表示負數。

例如正數7,在計算機中用一個8位的二進制數來表示,是00000111,而負數-7,則用10000111表示,這里的00000111和10000111是機器數

2、真數

計算機中的機器數對應的真實的值就是真數,對最高位(符號位)后面的二進制數轉換成10進制,並根據最高位來確定這個數的正負。對於上面的00000111和10000111來說,對最高位后面的二進制數轉換成10進制是7,在結合最高位的值,得出對應的真數分別是7和-7

3、原碼

用第一位表示符號,其余位表示值。因為第一位是符號位,所以8位二進制數的取值范圍就是:[1111_1111 , 0111_1111]  即 [-127 , 127] ,原碼是容易被人腦所理解的表達方式

4、反碼

正數的補碼反碼是其本身,負數的反碼是符號位保持不變,其余位取反。例如正數1的原碼是[0000_0001],它的反碼是是其本身

[0000_0001],-1的原碼是[1000_0001],其反碼是[1111_1110]

5、補碼

正數的補碼是其本身,負數的補碼是在其反碼的基礎上+1,例如正數1的原碼是[0000_0001],他的補碼是其本身[0000_0001],

-1的補碼是[1111_1111]

(2)反碼、補碼的由來

因為人腦可以知道第一位是符號位,可以根據符號位對真值的絕對值進行加減乘除,但是對於計算機來說,加減乘除是最最最基本的運算,要設計的盡量簡單,計算機辨別符號位會讓計算機的設計電路變得很復雜,於是人們想出了讓符號位也參與到運算上來。減去一個數,等於加上他的負數。

使用原碼參數運算的缺陷

 

 

從上面的原碼表中可以看見左邊每增加一個二進制單位對應的真數是遞減的,而右邊每增加一個二進制單位對應的真數是遞增的,所以對於原碼來說,能滿足正數的加法,但無法滿足負數的加法

2+1 = [0000_0010]原+[0000_0001]原=[0000_0011]原 = 3

1+-1=[0000_00001]原+[1000_0001]原=[1000_0010]原=-2

為了滿足負數對加法的需求,就必須讓負數與他對應的二進制碼是同步遞增或者同步遞減

於是就通過符號位不變,其余位取反來滿足這個同步遞增或者遞減的要求,由於正數本來就滿足它本身的加法,所以不需要做任何改變。這就是反碼的定義由來。

 

 

從上圖的反碼表中可以看到在運算不跨過0的時候,正負數的加法已經能滿足要求

-2+1=[1111_1101]反+[0000_0001]反=[1111_1110]反=-1

127+1=[1000_0000]反=-127=128 加法算出來是128,由於128超過最大值,余1,所以取最小值開始的第一位,也就是

最小值-127,但是這里有個不合理的地方,就是[1111_1111]和[0000_0000]都表示0,這導致在實際計算中每當跨過0一次,就有一個單位的誤差

-1+2=[1111_1110]反+[0000_0010]反=[0000_0000]反=0

要解決這個問題就必須讓反碼中的[1111_1111]和[0000_0000]合並,

由於[1111_1111]+[0000_0001]=[0000_0000],所以在負數反碼的基礎上+1就可以解決反碼中跨0的誤差問題,同時不會對負數與它對應的二進制反碼的同步遞增產生影響,所以在反碼的基礎上+1就完美的解決了符號參與預算的問題,這就是補碼為什么是在負數反碼的基礎上+1的由來。

 

 

從上面的圖中發現還有一個[1000_0000]的二進制沒有對應任何真數,於是就規定了這個數的真數是-128

所以補碼的表示范圍是[-128~127] ,這樣一來256個二進制正好表示256個整數,在實際二進制的運算中超過范圍其實就是對256的取余預算(x+128)mod 256 - 128。

(三)總結

對於有符號的數而言:

1、二進制的最高位是符號位:0表示正數,1表示負數

2、正數的原碼、反碼、補碼都一樣:三碼合一

3、負數的反碼=原碼的符號位不變,其它按位取反

4、負數的補碼=反碼+1,負數的反碼=補碼-1,反碼再求原碼=符號位不變,其它位按位取反

5、0的反碼、補碼都是0

6、Java沒有無符號數,換而言之、Java中的數都是有符號的

7、計算機對數的運算都是對數的補碼進行運算

8、計算機輸出結果時,輸出的是數的原碼

參考原文:1、https://blog.csdn.net/chenchao2017/article/details/79733278

                  2、https://blog.csdn.net/afsvsv/article/details/94553228


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM