1. 程式人生 > >2018-2019-1 20189221 《深入理解計算機系統》第 2 周學習總結

2018-2019-1 20189221 《深入理解計算機系統》第 2 周學習總結

2018-2019-1 20189221 《深入理解計算機系統》第 2 周學習總結

《深入理解計算機系統》第二章

本章講述了計算機的算術運算,重點描繪了無符號數和數的補碼錶示的特性。

資訊儲存

計算機字長,指明指標資料的標稱大小。32位機器虛擬地址空間為4GB。64位為16EB。64位機器可以執行32位機器編譯的程式,反過來不行。

定址和位元組順序:多位元組物件在記憶體中的存放方式分為小端法和大端法。例如一個int有4個位元組[x4,x3,x2,x1],x4位最高位,若x4在最前面(低地址)則為大端法,若x1在最前面則為小端法。大多數Intel相容機都只用小端模式(也就是低地址放低位,高地址放高位)。大多數IBM的使用大端。

大小端產生的問題:1)在不同型別的機器之間通過網路傳輸二進位制資料(用協議解決)2)在閱讀表示整數資料的位元組序列時。3)編寫規避正常的型別系統的程式時。

字串表示:字串被編碼為一個以null(‘\0’)字元結尾的字元陣列。每個字元用某個標準編碼來表示,常見的為ASCII字元碼。擴充套件有Unicode,UTF-8,其中UTF-8相容了ASCII碼。

程式碼表示:不同機器的指令編碼是不同的,一般二進位制程式碼是不相容的。

布林運算:~非,&與,|或,^異或,位運算。

邏輯運算:邏輯運算認為所有非0引數表示TRUE,0表示FALSE。對應OR(||)、AND(&&)和NOT(!)。如果第一個引數求值就能確定表示式的結果,那麼邏輯運算子就不會對第二個引數求值。

移位運算:左移,x<<k,丟棄最高的k位,右端補k個零。右移分為邏輯右移和算術右移。邏輯右移在左端補0,算術右移在左端補最高位,在有符號的整數(最高位為

利用數字的算數右移,然後利用0XFF這樣的數字做掩碼運算,可以獲取到一個數字的符號位。計算機的移位運算有一種很重要的作用就是利用掩碼運算去提取一個位模式的一段資訊。

C語言中的條件語句、條件運算子可以用移位的方式來做。

整數表示

無符號整數直接用其二進位制數值表示。

有符號整數用補碼編碼,最高位為符號位,1表示負數,0為非負。負數的補碼為原碼的反碼加1,正數的補碼為本身。補碼錶示的範圍,以4位為例,1000表示最小(-8),最大為0111(7),1111表示-1,0000表示0。

補碼的範圍是不對稱的,|Tmin|=|Tmax|+1,C語言中檔案<limits.h>定義了一組常量,來限定編譯器執行時整數的範圍,有INT_MAX,INT_MIN,UINT_MAX等。

為了保證程式的相容性,ISO C99標準在檔案stdint.h中引入了整數型別類,定義瞭如int32_t和int64_t這樣恆定長度的整數型別。

在C語言中,允許強制型別轉換,轉換規則是數值可能會變化,位模型不變。

在進行位擴充套件操作的時候,比如將一個32位的有符號數擴充套件到64位,那麼在保證原來的值不變的情況下,把31個低位擴充套件到64位的低位上,而最高的符號位擴充套件到高33位上。

將一個無符號數轉換為一個更大的資料型別,直接補零就可以,這叫零擴充套件。將一個有符號數轉換為一個更大的資料型別,補符號位,叫符號擴充套件。

整數運算

無符號加法:溢位直接去除高位。

有符號加法:當做無符號數進行加法,溢位直接截斷。

有符號的非:-x=~x+1,即等於按位取反再加1.

有符號數的乘法:xy=(x的補碼y的補碼)的補碼

整數乘以常數:用移位和加法以及減小來代替乘法,無論x是無符號的還是有符號的,其計算結果一致。

浮點數

浮點數表示(IEEE標準):

\[ V=(-1)^S*M*2^E \]

符號位s:複數s=1,正數s=0

尾數M:是一個二進位制小數

階碼E:對浮點數加權,權重為2,可以為負數。

浮點數規格化步驟:

(1)將一個浮點數變為二進位制,並且寫成1.x的科學記數法形式,注意是2進位制,基數是2.這樣的話,小數點後面的就是尾數部分,可以在尾數部分後面補足0,如果是單精度的話,要保證尾數的一個23位。

(2)因為在計算階碼的時候會用到E = exp - Bias, 所以exp = E+ Bias。這裡我要強調的是,我們在寫數字的時候,所看的那個階碼就是E,比如1.00000*2^12,,那麼此時12是E不是exp這個位模式所代表的值。

(3)最後把對應的三個位置上的位模式寫入對應的位置即可。

浮點數運算:

(浮點數的表示不像是整數,整數是能夠表示確切值的,但是浮點數卻不能,它是有可能做一些四捨五入的操作的,所以只是編碼,不能代表準確值,因為尾數和階碼等等都是有精度限制的,有些我們能夠手寫出來的浮點數,但是計算機並不一定能夠表示出來。)

在浮點數運算的時候,可能會出現這樣兩個問題:

一是加法中,兩個數的階碼不同,需要調整尾數,以便兩個數的小數點能夠對齊,然後相加。

二是乘法中,乘法時兩乘數的指數可能都很大,存在溢位可能。所以首先計算出運算準確的結果,然後在進行舍入操作,使得結果能夠控制在規定的精度內

(a)舍入操作的種類:1.向0舍入 2.無限向負無窮舍入 3.無限向正無窮舍入 4.向最近的舍入(貌似看起來是最好的辦法,但是一個數在兩個整數中間的時候,這種情況會出問題)5.向偶數舍入

(b)但是要注意的是,在進行帶有舍入操作的運算的時候,是不能運用結合律還有分配律的。這兩個數學運算定律在帶有舍入操作的浮點數運算裡是不適用的。

(3.14 + 1e10) - 1e10   !=   3.14 + (1e10 - 1e10)    1e20 * (1e20 - 1e20)  !=   (1e20 * 1e20) - (1e20 * 1e20)

預設的情況下,浮點數的舍入方式是向偶數舍入。

C語言中的浮點數:

第一個要點也是我很熟悉的,以前在打ACM比賽的時候老師經常強調的一點就是不要用==符號去比較浮點數,那樣會出問題。事實上很多數學函式以及運算子用在浮點數上都會出現問題,所以還是要慎重的好。最好的判斷兩個浮點數是否相等的辦法就是使用減法,如果兩者的結果是一個非常非常小的量,那麼就可以近似的認為這兩個浮點數是相等 的。

浮點數和整數之間的轉化:

從int ---> float可能會發生舍入,但是不會發生溢位

從int --> double,如果Int的值是在53位以下的(包括53位),會得到一個精確的轉換。

從float --> double, 我們會得到一個精確的轉換因為double的精度遠遠大於float的精度

從float, double -- > int,這樣的轉化可能會有問題,一個是從單精度浮點數到Int,由於階碼的存在,要調整尾數的尾數,所以在移位操作的時候可能會丟掉一些低有效位。並且這樣的轉化會按照向0舍入的操作去進行處理資料。另一個問題是浮點數可能會遠遠大於或者小於整型能夠表示範圍,因此我們把兩種型別的浮點數的比整型最小值還要小的變為Tmin,並且一些在浮點數中特殊的值,我們會將它們都轉化為Tmin或者Tmax。

課後習題

  • 2.61
  • 2.62