Java架構師成長之道之計算機組成原理計算篇

Java架構師成長之道之計算機組成原理計算篇

3.1 進制運算基礎

3.1.1 進制的概述

進制的定義:進制是一種計數方式,也稱爲進位計數法或者位值計數法,使用有限數字符號表示無限的數值,使用的數字符號的數目稱爲這種進位制的基數或者底數,例如十進制就是由0-9十個數字組成。html

在計算機內存中,都是以二進制的補碼形式來存儲數據的,生活中以十進制方式計算的數據居多,例如帳戶餘額,開發人員的薪水等等。計算的內存地址、MAC地址等等一般都是使用十六進制表示的,Linux系統的權限系統採用八進制的數據表示的。編程

相同進制類型數據進行運算時會遵照加法:逢R進1;減法:借1當R,其中R就表示進制。數組

以下表格是計算機經常使用進制的組成、示例和使用場景:架構

進制名稱 組成 數值示例 典型使用場景
二進制 0,1 101 內存數據存儲
八進制 0-7之間的8個整數 012(以0開頭) Linux權限
十進制 0-9之間的10個整數 12 整數
十六進制 0-9,a-f之間的10個數字加6個字母 12f 數據的內存地址

3.1.2 計算機底層爲何只能識別二進制

咱們目前主要使用的計算機都是大規模集成電路機,是採用大規模和超大規模的集成電路做爲邏輯元件的。學習

集成電路,按其功能、結構的不一樣,能夠分爲模擬集成電路、數字集成電路和數/模混合集成電路三大類。而咱們的計算機主要是採用數字集成電路搭建的。spa

邏輯門是數字邏輯電路的基本單元。常見的邏輯門包括「與」門,「或」門,「非」門,「異或」等等。經過邏輯門能夠組合使用實現更爲複雜的邏輯運算和數值運算。code

邏輯門能夠經過控制高、低電平,從而實現邏輯運算。電源電壓大小的波動對其沒有影響,溫度和工藝誤差對其工做的可靠性影響也比模擬電路小得多,因此相對穩定。orm

由於數字計算機是由邏輯門組成,而邏輯電路最基礎的狀態就是兩個——開和關。因此,數字電路是以二進制邏輯代數爲數學基礎。二進制的基本運算規則簡單,運算操做方便,這樣一來有利於簡化計算機內部結構,提升運算速度。htm

可是在平常開發中,一般都會使用八進制和十六進制,由於八進制和十六進制相對於二進制表示數據更加簡潔,並且一個八進制表示三個二進制,一個十六進制表示四個二進制。blog

例如 1024使用二進制表示爲0b100 0000 0000,使用八進制表示爲0o2000,使用十六進制表示爲0x400。

3.1.3 二進制運算的基礎

首先明確不一樣進制的值是如何計算的,這裏以十進制和二進制爲例子,闡述它們的計算過程。

十進制1024

1024=1*10^3+2*10^1+4*10^0=1000+20+4=1024

二進制的0b10000000000

0b10000000000 =1*2^10=1024

3.2 進制之間的轉換

3.2.1 二進制轉十進制(整數)

二進制整數轉十進制整數是使用按權展開法計算的,這裏以二進制數據01100101爲例子。
從右往左開始數,若是二進制位爲1,則依次用1*2^n,n從0開始。

01100101 轉換爲十進制的計算過程以下所示

01100101=1*2^6+1*2^5+1*2^2+1*2^0=64+32+4+1=101

3.2.2 十進制轉二進制(整數)

十進制整數轉二進制整數是採用重複相除法來實現的,具體的實現就是將十進制的整數除以2,求餘數,直到商數爲0,而後將餘數倒轉的結果就是十進制轉二進制的結果。

以十進制101爲例子,轉換爲二進制的計算過程以下表格所示

重複除以2 商數 餘數
101/2 50 1
50/2 25 0
25/2 12 1
12/2 6 0
6/2 3 0
3/2 1 1
1/2 0 1

而後將餘數的結果從下到上串聯起來的結果:1100101,即十進制的101轉換爲二進制的結果爲1100101

再來一個例子:將十進制的237轉換爲二進制

重複除以2 商數 餘數
237/2 118 1
118/2 59 0
59/2 29 1
29/2 14 1
14/2 7 0
7/2 3 1
3/2 1 1
1/2 0 1

而後將餘數的結果從下到上串聯起來的結果:11101101,即十進制的237轉換爲二進制的結果爲11101101。

3.2.3 二進制轉十進制(小數)

二進制的小數轉換爲十進制的小數也是使用按權展開法計算的,只不過首先是從左向右數,從2-1依次遞減開始計算的,2-1就是除以2,2^-2就是除以4,依次類推。

例如小數0.11001轉換爲十進制的計算過程以下所示。

0.11001=1*2^-1+1*2^-2+1*2^-5=0.5+0.25+1/32=0.75+0.03125=0.78125=25/32

再將一個二進制的小數轉換爲十進制

0.01011=1*2^-2 +1*2^-4 +1*2^-5 =0.25+0.0625+0.03125=0.34375=11/32

3.2.4 十進制轉二進制(小數)

十進制的小數轉換爲二進制的小數使用重複相乘法來計算的。

下面以一個小數0.78125爲例子,介紹轉換二進制的過程。
0.78125轉換爲分數的形式就是25/32

重複乘以2 取1
25/32 50/32=1+9/16 1
9/16 18/16=1+1/8 1
1/8 2/8=0+1/4 0
1/4 2/4=0+1/2 0
1/2 2/2=1+0 1

而後再將取1的結果從上到下串聯起來,即0.78125轉換爲二進制的結果是0.11001

再計算一個小數0.34375,轉換爲分數形式爲11/32,計算步驟以下所示

重複乘以2 取1
11/32 22/32=0+11/16 0
11/16 22/16=1+3/8 1
3/8 6/8=0+3/4 0
3/4 6/4=1+1/2 1
1/2 2/2=1+0 1

而後再將取1的結果從上到下串聯起來,即0.34375轉換爲二進制的結果爲0.01011。

3.3 二進制數據的表示方法

3.3.1 有符號數和無符號數

在十進制中使用加號(+)表示整數,使用減號(-)表示負數,那麼負數在計算機中是如何表示的呢?

首先以正整數127(佔1個字節)爲例子,轉換爲二進制的結果是01111111,那麼-127如何表示呢,結果是11111111,由於計算機在存儲數據時,按照符號位和數字位組成,其中符號位是二進制數據的左邊第一位數字,若是是0,則表示該數字是整數,例如01111111,若是是1表示該數字爲負數,例如11111111,這樣的表示方法就是原碼錶示法,原碼錶示法在表示數據時有以下特色:

  1. 使用0表示正數,使用1表示負數
  2. 規定數值的最高位是符號位
  3. 表達簡單明瞭,是人類最容易理解的方法

前面在進行進制轉換的使用使用的按權展開法,重複相乘法,重複相除法都是基於二進制原碼錶示法進行操做的。

可是原碼錶示法有有些缺陷,好比說在使用原碼錶示0的時候,這裏以一個字節爲例:0的正數表示爲00000000,0的負數是10000000,無論正0和負0其實都是0,容易產生歧義。

原碼錶示法在進行數據計算的時候特別複雜,特別是兩個操做數符號位不相同的時候,主要須要如下步驟:

  1. 判斷兩個操做數的大小
  2. 使用絕對值大的數字減去絕對值小的數字
  3. 對於符號值,以絕對值大的爲準

3.3.2 二進制的補碼錶示法

引進補碼的目的:

  • 減法運算複雜,但願找到正數代替負數的方法
  • 使用加法運算代替減法運算,從而消除減法。
    補碼的計算方式公式以下所示
x>0, x=x
x<0,x=2^(n+1)+x

其中n表示二進制的位數,以一個字節爲例,那麼n就是8,若是是兩個字節,那麼n就是16,依次類推。

補碼的計算案例

  1. 利用補碼的計算公式計算一個正數例子:假設n=8,x=13,計算x的原碼和補碼

13的原碼以一個字節表示就是00001101。
而13大於0,所以13的補碼和原碼同樣,也就是00001101。

  1. 利用補碼的計算公式計算一個負數的例子:假設n=8,x=-13,計算x的原碼和補碼

-13的原碼爲10001101,由於是負數,因此最高位爲-1

而-13的補碼能夠根據公式x=2^n+1+x

x=2^(8+1)+ -13=512-13=499=1 1111 0011

而 1 1111 0011已經超出了一個字節表示的數據範圍(-128-127),因此須要將最左邊的1截取掉,所以-13的補碼結果爲1111 0011。

  1. 利用補碼的計算公式計算負數的補碼:假設n=8,x=-7,計算x的原碼和補碼
    -7的原碼爲 10000111
    -7的補碼能夠根據公式x=2^(n+1)+x
x=2^(n+1)+x=2^9+ -7=512-7=505=1 1111 1001

一樣的道理,1 1111 1001超過了一個字節的表示範圍(-128-127),因此須要將最左邊的1截取掉,即-7的補碼錶示爲11111001。

  1. 利用補碼的公式計算負數的補碼:假設n=8,x=-1,計算x的原碼和補碼
    -1的原碼爲10000001
    -1的補碼能夠根據公式x=2^(n+1)+x
x=2^(8+1)+ -1=512-1=511=1 1111 1111

一樣的道理,1 1111 1111超過了一個字節的表示範圍(-128-127),因此須要將最左邊的1截取掉,即-1的補碼錶示爲11111111。

以上的例子在計算補碼的過程當中仍是使用了減法實現計算。

3.3.3 二進制的反碼錶示法

反碼出現的目的就是找出原碼和補碼的規律,消除轉換過程當中的減法。
反碼的計算公式以下所示

x>0, x=x
x<0,x=(2^(n+1)-1)+x

反碼計算案例

  1. x=-13,n=8,計算x的原碼和反碼

-13的原碼是1000 1101
-13的反碼能夠根據公式x=(2^(n+1)-1)+x

x=(2^(8+1)-1)+ -13=511-13=498=1 11110010

因爲1 11110010超過了一個字節的表示範圍(-128-127),因此須要將最左邊的1截取掉,即-13的補碼錶示爲11110010。

2.x=-7,n=8,計算x的原碼和反碼
-7的原碼爲10000111
-7的反碼能夠根據公式x=(2^(n+1)-1)+x

x=(2^(8+1)-1)+ -7=511-7=504=1 11111000

因爲1 11111000超過了一個字節的表示範圍(-128-127),因此須要將最左邊的1截取掉,即-7的反碼錶示爲1111000。

這裏採用一個字節存儲,總結下以前使用過的十進制整數7,-7和13,-13的原碼、補碼、反碼

十進制 原碼 補碼 反碼
7 7 7 7
-7 10000111 11111001 1111000
13 13 13 13
-13 1000 1101 1111 0011 11110010

根據以上表格的數據能夠獲取到如下結論

  1. 整數的原碼、反碼和補碼都是同樣的
  2. 負數的原碼求反碼,最高位不變,其餘位取反
  3. 負數的反碼求補碼,反碼加1

根據規律計算原碼、反碼和補碼的案例

1.x=-7,求原碼、反碼和補碼
-7的原碼是1000 0111,反碼是1111 1000,補碼是1111 1001

2.x=-9,求x的原碼、反碼補碼
-9的原碼是100001001,反碼是111110110,補碼是11110111

原碼、補碼、反碼總結:
因爲原碼存在着表示0有歧義,減法運算複雜的問題,所以引進了補碼解決了這倆問題,可是在原碼轉換爲反碼的計算過程當中仍是使用了減法,所以引進了反碼則是消除了原碼計算補碼時須要使用減法,原碼轉換爲反碼只須要最高位不變,其餘位取反便可,而反碼轉換爲補碼只須要在反碼的基礎上加1便可,源碼計算反碼經過先求反碼,再求補碼消除了減法

3.3.4 小數的二進制補碼錶示法

首先回顧下整數的二進制補碼錶示法的計算公式

x>0, x=x
x<0,x=2^(n+1)+x

而小數的二進制補碼錶示法的計算公式以下所示

x>0, x=x
x<0,x=2+x

小數的二進制補碼計算案例

  1. x=9/16,計算x的原碼,反碼和補碼
    首先將十進制小數9/16轉換爲二進制,計算流程以下
重複乘以2 取1
9/16 18/16=1+1/8 1
1/8 2/8=0+1/4 1
1/4 2/4=0+1/2 0
1/2 2/2=1+0 1

即9/16的二進制轉換結果爲0,0.1101,默認的轉換結果爲原碼錶示,由於9/16是正數,所以其二進制的原碼、反碼和補碼都是0,0.1101。

  1. x=-(11/32),計算x的原碼、反碼和補碼
    首先將十進制小數數-(11/32)轉換爲二進制,計算流程以下
重複乘以2 取1
11/32 22/32=0+11/16 0
11/16 22/16=1+3/8 1
3/8 6/8=0+3/4 0
3/4 6/4=1+1/2 1
1/2 2/2=1+0 1

即-(11/32)的二進制轉換結果爲1,0.01011,默認的轉換結果爲原碼錶示,還須要求x的反碼和補碼,x的反碼是1,1.10100,x的補碼是1,1.10101。

3.4 二進制數據的運算

3.4.1 定點數與浮點數

定點數的表示方法:定點數就是小數的固定在某個位置的數。

定點數有兩種表示方法,第一種是小數點在符號位和數值位數的中間,這種被稱爲純小數,以下表格所示

數值 符號位 數值位
0.1011 0 1011
-0.1011 1 1011

第二種是小數點在數值位的最後面,這種被稱爲純整數,以下表格所示

數值 符號位 數值位
1011 0 1011
1011 1 1011

若是想要表示的數據不是純整數也不是純小數,此時必須乘以比例因子以知足定點數保存格式,例如二進制10.01能夠經過將小數點左邊移兩位知足純小數的表達方法,或者經過將小數點右邊移動兩位知足純整數的表達方法。

3.4.2 浮點數的表示方法

首先明確浮點數的由來,由於計算機常常處理的數據絕大部分都不是純小數或者純整數,並且當數據的範圍很大,難以用定點數表示,而且定點數不夠靈活,所以出現了浮點數。

浮點數的表示形式
爲了瞭解浮點數的表現形式,首先回一下學校學過的科學計數法。
例如整數123450000使用科學計數法表示爲1.2345*10^8,其中1.2345表示尾數,10表示基數,8表示的是階碼,在浮點數的表示格式中也存在尾數、基數和階碼的概念。

對於任意的浮點數均可以使用以下公式轉換

N=S*r^j

其中S表示尾數,r表示基數,j表示階碼。

例如二進制小數 11.0101=0.110101210,須要指出的是210的10指的是2的二進制表示方式,並非十進制的10
11.0101還能夠表示爲0.0110101
211,須要指出的是211的11指的是3的二進制表示方式,並非十進制的11。

3.4.3 浮點數在計算機中的存儲

在計算機內部,浮點數的存儲包含四部分,分別是 階碼符號位、階碼數值位、尾數符號位、尾數數值位,由於階碼和尾數多是負數,因此有符號位,並且浮點數的尾數必須是純小數。

例如二進制的11.0101按照不一樣的階碼在內存的存儲方式爲
11.0101=0.1101012^10 階碼爲二進制的10
11.0101=0.0110101
2^11 階碼爲二進制的11

二進制浮點數數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位(8位)
0.110101*2^10 0 10 0 11010100
0.0110101*2^11 0 11 0 01101010

因爲這裏的尾數數值必須知足8位,若是不足8位,須要用0補足。

3.4.4 浮點數的表示範圍

因爲浮點數是由階碼和尾數組成,所以考慮浮點數的表示範圍實際上就是階碼和尾數的取值範圍。
這裏方便理解假設階碼的數值有m位,尾數的數值有n位,對於任意一個浮點數,階碼錶示的最大值就是2^m-1,假設階碼有8位而且全是1,那麼這個階碼錶示的最大值就是255,若是考慮符號位,那麼階碼的取值範圍就是-(2^m-1) - 2^m-1,那麼8位數階碼的取值範圍就是-255 - 255

尾數要求是純小數,尾數能表示的最大值1-2^-n,尾數所能表示的最小值2^-n,所以尾數的表示範圍是2^-n - 1-2^-n,若是考慮符號位,尾數的取值範圍是
負數:-(1-2^-n) - -(2^-n)
正數: 2^-n - 1-2^-n

因此浮點數表示的最小負數值是-(1-2^-n)*2^(2^m-1) ,最大的負數是-(2^-n)*2^-(2^m-1)
浮點數表示的最大的正數值是(1-2^-n)*2^(2^m-1),最小的正數值是(2^-n)*2^-(2^m-1)

若是超過了浮點數表示的最大值則會發生數據溢出,稱爲上溢(數值太大)。
若是超過了浮點數表示的最小值則會發生數據溢出,稱爲下溢(數值過小)。

平常開發中常用單精度和雙精度浮點數,其中單精度是使用4個字節即32位存儲的浮點數
而雙精度是使用8個字節即64位存儲的浮點數。

3.4.5 浮點數的規格化

首先回到以前的科學計數法的例子:123450000=1.2345*10^8,科學計數法規定了尾數必須在1-10之間,例如12345 000 0000=12.345*10^10,12.345超過了尾數的範圍則會不符合要求。

一樣在浮點數中的尾數也有相關的要求

  1. 尾數必須是純小數
  2. 尾數最高位必須是1

符合浮點數規格化的表示方法案例

11.0101=0.110101*2^10

尾數的最高位不是1,不符合規範

11.0101=0.0110101*2^11

尾數的最高位不是1,不符合規範

11.0101=0.00110101*2^100

尾數不是純小數,不符合規範

11.0101=1.10101*2^1

浮點數階碼與尾數的案例

1.假設浮點數字長16位,尾數爲11位,階碼爲5位,將十進制數13/128表示爲二進制的浮點數

首先明確這裏的浮點數由1位尾數符號位加上10位尾數數值加上1位階碼符號位加上4位階碼數值組成。

而後將十進制數13/128轉換爲浮點數,計算過程以下所示

重複乘以2 取1
13/128 26/128=0+13/64 0
13/64 26/64=0+13/32 0
13/32 26/32=0+13/16 0
13/16 26/16=1+5/8 1
5/8 10/8=1+1/4 1
1/4 2/4=0+1/2 0
1/2 2/2=1+0 1

十進制13/128轉換爲二進制的原碼結果是0.0 001 101 000,因爲正數的原碼、反碼、補碼同樣,這裏不須要轉換成補碼。然後面的三個0是爲了知足尾數數值爲10位的要求

再按照規格化的要求轉換浮點數,向左移動3位(乘以2的-3次方)便可知足尾數最高位必須是1
0.0001101000=0.1101000*2^-11,其在計算機的存儲格式以下表格所示

數值 階碼數值 階碼符號 尾數數值 尾數符號
0.1101000*2^-11 0011 1 1101000000 0

2.假設浮點數字長16位,尾數爲11位,階碼爲5位,將十進制數-54表示爲二進制的浮點數

首先明確這裏的浮點數由1位尾數符號位加上10位尾數數值加上1位階碼符號位加上4位階碼數值組成。

而後將-54轉換爲二進制,-54的原碼錶示方式爲1,11 0110,逗號左邊的1表示爲負數,而後再將110110按照浮點數規格化的要求轉換110110=0.110110*2^110

而後再按照16位浮點的字長轉換
首先是尾數爲10位,即110110轉換成110110 0000,轉換以後的反碼爲001001 1111,尾數的補碼是00101 0000 ,,因爲尾數補碼的最高位是0,所以尾數符號的結果就是1。

尾數肯定以後就能夠計算階碼,階碼符號是0,由於階碼是正數,而階碼數值是0110,由於要知足接碼數值的位數是4位,最後就能夠計算出來-54在計算機中是如何存儲的了

數值 階碼數值 階碼符號 尾數數值 尾數符號
0.110110*2^110 0110 1 00101 0000 0

須要注意的是,計算機的數據最終是以補碼的方式存儲的。,所以這裏的尾數數值取得是補碼的結果

3.4.6 定點數和浮點數的對比

  • 當定點數和浮點數尾數相同時,浮點數表示的範圍更大
  • 當浮點數尾數爲規格化數時,浮點數的精度更高
  • 浮點數的運算包含階碼和尾數,浮點數的運算更加複雜
  • 浮點數在數的表示範圍、精度、溢出處理、編程等方面均優於定點數
  • 定點數在運算規則、運算速度、硬件成本優於浮點數
  • 目前絕大多數計算機都是採用浮點數運算,而定點數使用在成本比較低的芯片中

3.5 定點數和浮點數的運算

3.5.1 定點數的加法運算

定點數的加法分爲整數部分和小數部分,例如兩個定點數A和B相加

整數加法: A的補碼+B的補碼=(A+B)的補碼(mod2^n+1)
小數加法: A的補碼+B的補碼=(A+B)的補碼(mod2)

在實際運算時,數值位與符號位一同參與運算,並將符號位產生的進位天然丟掉,也就是(mod2^n+1)和(mod2)的操做。

這裏先列出原碼以及反碼的計算公式

原碼=補碼取反加1
補碼=原碼取反加1

定點數的加法運算案例:

1.假設 A=-110010, B=001101,求A+B
首先求A -110010的補碼 求反碼結果是001101,求補碼的結果是1,001110,其中最左邊的1表示符號位。因爲B是正數,所以B的補碼就是B的原碼,也就是001101。

符號位與數值位計算過程
A+B=A的補碼+B的補碼=(A+B)的補碼(mod2^n+1)=1,011011=-100101

1,001110
        0,001101
        1,011011

1,0111011 表示爲補碼,還須要轉換爲原碼,補碼首先減去1求反碼的結果是1,011010,反碼求原碼的結果是100101,即最終A+B的結果是-100101。

2.假設A=-0.1010010,B=0.0110100,求A+B的和
首先求出A的補碼,1,0.1010010的反碼是1,1.0101101,補碼是原碼末位加1,結果爲1,1.0101110
因爲B的最高位是0,所以B的補碼是0.0110100。

符號位與數值位一同計算的過程

11.0101110
00.0110100
11.1100010

A+B=A的補碼+B的補碼=1,1.0101110+0,0.0110100=1,1.1100010

而後將補碼1,1.1100010求反碼的結果是1,0.0011101,再將末位加1,求原碼結果爲1,0.0011110,也就是A+B的最終結果是-0.00111100

3.A=-10010000,B=-01010000,求A+B的和
首先計算出A的補碼,即原碼取反加1的結果爲1, 01110000
而後再計算忽B的補碼,即原碼取反加1的結果爲1,10110000

而後再將符號位和數值位一同參與運算,計算過程以下

1,0111 0000
    1,1011 0000
  11,0010 0000

因爲數值位和符號位一同運算時發生了進位,此時符號位產生的進位天然丟掉
即A+B=A的補碼+B的補碼=1,01110000+1,10110000=1,0010 0000
1,00100000的反碼是1,11011111,而後在末位加1,即A+B的結果是-11100000

4.A=-10010000,B=-11010000,求A+B的和

首先計算A的補碼1,10010000取反的結果是1,01101111,而後加1的結果是1,01110000。
而後計算B的補碼1,11010000取反的結果是1,00101111,而後加1的結果是1,00110000。

即A+B=A的補碼+B的補碼=1,01110000+1,00110000

而後再將符號位和數值位一同參與運算,計算過程以下

101110000
    100110000
  1010100000

因爲數值位和符號位一同運算時發生了進位,此時符號位產生的進位天然丟掉
所以A+B=A的補碼+B的補碼=1,01110000+1,00110000=0,10100000,因爲最高位是0,所以A+B的原碼和補碼一致,也就是A+B的最終結果是10100000。

負數和負數相加的結果應該是負數,可是這裏的結果10100000是正數,顯然結果是不正確的,這裏咱們將二進制的運算數據轉換爲十進制相加,即-144+ -208=-352,正確的運算結果的十進制值是-352。

由於這裏發生了溢出現象,咱們使用1個字節的數值存儲了-352,超過了它的表示範圍。

咱們能夠採用雙符號位判斷法來判斷數據在運算的過程當中是否發生了溢出現象。
所謂的雙符號位判斷法就是將原來用單符號位表示成雙符號位,即0換成00,1換成11,並且在運算過程當中,雙符號位運算所產生的進位也會丟棄,而結果的雙符號位不一樣則表示溢出,一旦發生了溢出現象也就意味着計算結果是不正確的

雙符號位判斷法的案例
1.A=-10010000,B=-11010000,使用雙符號位求A+B的和
首先計算A的補碼1,10010000取反的結果是1,01101111,而後加1的結果是1,01110000。
而後計算B的補碼1,11010000取反的結果是1,00101111,而後加1的結果是1,00110000。
即A+B=A的補碼+B的補碼=1,01110000+1,00110000

而後再將符號位和數值位一同參與運算,計算過程以下

1101110000
    1100110000
1 1010100000

因爲數值位和符號位一同運算時發生了進位,此時符號位產生的進位天然丟掉
所以A+B=A的補碼+B的補碼=11,01110000+11,00110000=10,10100000,因爲雙符號位不一樣,表示溢出,所以計算結果是錯誤的。

2.A=-10010000,B=-01010000,使用雙符號位求A+B的和
首先計算出A的補碼,即原碼取反加1的結果爲11, 01110000
而後再計算忽B的補碼,即原碼取反加1的結果爲11,10110000

而後再將符號位和數值位一同參與運算,計算過程以下

11,0111 0000
    11,1011 0000
1 11,0010 0000

因爲數值位和符號位一同運算時發生了進位,此時符號位產生的進位天然丟掉
即A+B=A的補碼+B的補碼=11,01110000+11,10110000=11,0010 0000,因爲11表示雙符號相同,即計算結果爲沒有溢出。
11,00100000的反碼是11,11011111,而後在末位加1,即A+B的結果是-11100000

3.5.2 定點數的減法運算

定點數的減法運算也分爲整數減法和小數減法兩個部分,例如兩個定點數A和B相減法有以下公式。

整數減法:A的補碼-B的補碼=(A+ -B)的補碼(mod2^n+1)
小數減法:A的補碼-B的補碼=(A+ -B)的補碼(mod2)

減法運算實際上仍是轉換成了加法運算,即減去一個數等於加上這個數的負數,而-B的補碼等於 B的補碼連同符號位按位取反,末位加1。

例如B的補碼等於1,0010101,那麼-B的補碼就是0,1101011。

定點數減法運算案例

A=11001000,B=-00110100,求A-B
首先求A的補碼,因爲A是正數,所以A的補碼是0,11001000
由於A-B= A+ -B
因此先求出B的補碼,1,00110100的反碼是1,11001011,而後再加1的結果是1,11001100。
而後再求出-B的補碼0,00110100。

所以A-B=11001000+00110100

00,11001000
00,00110100
00,11111100

即A-B=11111100

3.5.3 浮點數的加減法運算

首先使用x,y分別表示兩個浮點數,根據以前學習的浮點數表示法知道

對於任意一個浮點數,均可以使用N=S*r^j 來表示,所以x,y分別使用以下形式表示。

x=S * r^j
y=S * r^j

其中S表示尾數,r表示基數,j表示階碼。

對於一個浮點數的加減運算,會經歷以下5個步驟

  • 對階
  • 尾數求和
  • 尾數規格化
  • 舍入
  • 溢出判斷
  1. 對階

對階的目的就是使得兩個浮點數的階碼一致,使得尾數能夠進行運算,由於浮點數的尾數運算實際上就是以前學習的定點數運算,相對簡單。可是浮點數位數的實際小數位階碼有關,若是階碼不對階則沒法進行浮點數的運算,而對階的階碼則會按照小階看齊大階的原則。

例如二進制x=0.1101*2^01,y=(-0.1010)*2^11,在計算機中的存儲以下表格所示,其中符號位使用雙位符號位存儲,而數值位使用4位存儲。

對階以前的存儲

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x 00 00 01 00 1101
y 00 0011 11 1010

小階看齊大階,也就是將x的階碼由01變成y的階碼11,x的尾數右邊移動兩位,左邊補上00,即x=0.001101*2^11,y=(-0.1010)*2^11,因爲尾數按4位存儲,所以捨去x的尾數0.001101的最後兩位數01。

小階看齊大階以後x,y在計算機中的存儲

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x 00 0011 00 0011
y 00 0011 11 1010
  1. 尾數求和

尾數的求和 和定點數的加減法同樣,使用補碼運算,減法運算轉換爲加法運算,即A-B=A+(-B)。

在x,y完成對階以後x=0.0011*2^11,y=(-0.1010)*2^11

首先求出二進制浮點數x,y 尾數的補碼

二進制浮點數x尾數的原碼爲00.0011 ,二進制浮點數y尾數的原碼爲11.1010

根據(負數)反碼=原碼取反,末位加1,正數 原碼=反碼=補碼的規則計算

二進制浮點數x尾數的補碼爲00.0011 ,二進制浮點數y尾數的補碼爲11.0110

將x和y的符號位和數值位一塊兒運算獲得尾數求和的結果 S=(x+y)[ 補碼]=00.0011+11.0110=11.1001

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x 00 0011 11 1001
  1. 尾數規格化
    尾數規格化須要判斷兩種狀況:分別是S[補碼]>0和S[補碼]<0
S>0   S[補碼]=00.1xxx
S<0   S[補碼]=11.0xxx

通常狀況下,若是不知足上面的格式,須要進行左移,左移N位,浮點數尾數的末位補N個0,依次類推,同時階碼發生相應的變化,以知足規格化的要求。即若是尾數符號位和尾數最高位不一致的狀況下須要進行尾數的規格化,若是雙符號位不一致的狀況下須要右移(定點運算溢出的狀況),若是是右移的話則須要進行舍入操做。

尾數規格化以前:

S=(x+y)[補碼]=`00.0011+11.0110=11.1001`

將11.1001左移一位,即將尾數的最高位1001的最左邊的1捨棄掉,由於尾數數值位只考慮四位,而後在尾數的末位補上0,11.1001 規格化 左移1位的結果是 11.0010
尾數規格化以後:

S=(x+y)[補碼]=`00.0011+11.0110=11.1001=11.0010

11.0010在計算機中的存儲以下表格所示

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x 00 0010 11 0010

尾數左邊移動N位,階碼數值位相應的減N位,例如這裏x的尾數左移1位,階碼由原來的
0011變成了0010。

S=(x+y)[補碼] =11.0010
計算機存儲採用的是補碼錶示法,而咱們看到的數據都是使用原碼錶示法表示的,所以這裏還須要將11.0010轉換爲原碼。
而11.0010原碼是11.1110,即-0.1110,因此x+y的結果是 -0.1110*2^10

  1. 舍入
    在舍入操做以前須要瞭解左移和右移

正數的右移,負數的無符號右移,就是相應的補碼移位所得,在高位補0便可。
負數的右移,就是補碼高位補1,而後按位取反加1便可。

浮點數規格化時若是雙符號位不一致的狀況下須要右移,而右移動則須要進行舍入的操做,在操做十進制數據時有時候會進行四捨五入,而對於二進制是零舍一入,等效於十進制的四捨五入。

例如S[補碼]=10.10110111,因爲雙符號位是10,因此是雙符號位不一致,此時須要進行右移操做,右移以後S[補碼]=11.01011011(1),而後進行零舍一入,由於尾數最後面一位是1,所以尾數末位須要加1,即11.01011011+1=11.01011100,右移的操做,若是考慮階碼的話,階碼也要加1,也就是S[ 補碼]=10.10110111舍入操做的結果是11.01011100。

零舍一入能夠提升尾數規格化的精度,可是零舍一入可能會發生溢出的狀況
例如S[補碼]=01.11111111,因爲雙符號位是01,所以須要進行右移規格化,採用零舍一入,由於最後面一位是1,所以尾數末位要加上1,即00.11111111+1=01.00000000,因爲右移動一位以後雙符號位是01,即雙符號位仍然不一致,還須要進行右移動操做,01.00000000右移一位的結果是00.1000000(0),即S[補碼]=01.11111111進行舍入操做後的結果是00.1000000。由於進行了兩次右移操做,階碼還須要加10(即十進制的2)。

  1. 溢出判斷
    在以前定點數加減法運算時採用了定點數雙符號位判斷法,即定點數運算結果雙符號位一致表示沒有溢出,雙符號位不一致則表示溢出。

可是在浮點數運算時雙符號位判斷法並不適用,浮點數運算尾數雙符號位不一致並不算溢出,由於當浮點數尾數雙符號位不一致時能夠右移把不一致的雙符號位運算符變成一致。

在浮點數中的溢出判斷主要是經過階碼的雙符號位判斷是否溢出,若是尾數規格化以後,階碼的雙符號位不一致,則認爲是溢出。

浮點數加減法運算的案例

例如 x=0.11010011*2^1101,y=0.11101110*2^1100,假設階碼4位,尾數8位,計算x+y的結果

  1. 對階

首先將x和y的值在計算機中的存儲表示出來,以下表格所示

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x 00 1101 00 11010011
y 00 1100 00 11101110

首先第一步進行對階的操做,按照小階對齊大階的原則,由於1101>1100,因此須要將y右移動1位來完成對階,y=0.011101110*2^1101,而按照尾數是8位的要求對階以後的結果以下表格所示

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x 00 1101 00 11010011
y 00 1101 00 01110111
  1. 尾數求和

因爲x,y都是正數,所以x[補碼]+y[補碼]=x[原碼]+y[原碼]=00.11010011+00.01110111=01.01001010,計算過程以下所示,

x  00.11010011
y  00.01110111
      01.01001010

尾數求和以後尾數的符號位結果是01,在定點數運算時算符號位不一致表示溢出,可是浮點數是根據階碼的雙符號位判斷是否溢出。

  1. 尾數規格化

浮點數 x+y 尾數求和的結果是01.01001010,因爲符號位不一致,所以進行右移操做,01.01001010 右移,即將01.01001010的最後一個0捨棄掉,而後把符號位補上一個0, 即01.01001010 右移1位的結果是 00.10100101

  1. 舍入

按照零舍一入的原則,00.10100101(0)舍入的結果是00.10100101,最終的結果以下表格所示

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x+y 00 1110 00 10100101
  1. 溢出判斷

溢出判斷是判斷階碼的符號位,即判斷00.10100101
00.10100101的階碼符號位爲00,因此沒有發生溢出,即x+y的最終結果是
x+y[原碼]=x+y[補碼]=0.10100101*2^1110

浮點數加減法的運算流程圖

浮點數加減法運算流程
浮點數加減法運算流程

3.5.4 浮點數的乘除運算

假設有兩個浮點數x,y,能夠採用以下表示方法

x=Sx*r^jx
y=Sy*r^jy

對於浮點數的乘法運算是按照階碼相加,尾數求積來運算的,即xy=(SxSy)*r^(jx+jy)

對於浮點數的除法運算時按照階碼相減,尾數求商來運算的,即x/y=(Sx*Sy)*r^(jx-jy)

浮點數的乘除法運算是按照階碼運算->尾數運算->尾數規格化->舍入->溢出判斷五個過程

例如二進制浮點數 x=0.11010011*2^1101,y=0.11101110*2^0001,假設階碼爲4位,尾數8位,計算x*y

x*y=(0.11010011 *0.11101110)*2^(1101+0001)=0.11000100*2^1110

即階碼運算和尾數運算以後x*y的值是0.11000100*2^1110 ,在計算機中存儲以下表格所示

數值 階碼符號位 階碼數值位 尾數符號位 尾數數值位
x*y 00 1110 00 11000100
相關文章
相關標籤/搜索