計算機系統結構-數據表示
數據表示:數據表示是指能由計算機硬件直接識別和引用的數據類型。(例如定點數浮點數)
表現在什么地方:表現在它有對這種數據類型進行操作的指令和功能部件。
數據結構種類:串,隊,列,棧,陣列,鏈表,樹,圖
什么是數據結構:它反映了應用中要用到的各種數據元素和或信息單元之間的結構關系。
數據表示
自定義數據表示
自定義數據表示,包括標志符的數據表示、數據描述符的數據表示。
標志符的數據表示
標識符的數據表示:指用於標識數據類型,例如負數、幾機制、浮點型等;
原理:讓計算機中每個數據都帶有類型標志符。
優點:可簡化指令系統和編譯程序,便於不同數據類型的自動校驗和檢驗。
缺點:一個標志位只能對一個數據進行描述。描述效率不高。
我們可以想象成 C# 中的值類型。
數據描述符的數據表示
跟標識符的數據表示類似,主要區別在於標識符的數據表示的標志符是跟數據在一起的;數據描述符的數據表示中,數據描述符是跟數據分開的。
數據描述符中包含數據的各種標志位、長度、數據地址。
我們可以想象成 C# 中的引用類型。
浮點數
對於一個浮點數,10進制情況下,我們可以使用以下公式表示小數部分
N = ±m * 10^e
N表示浮點數,m表示小數尾數,e表示位數。
例如 1100.1 = 0.1 * 10^3。
上面的是 10 進制情況下,而在計算機系統中,一般使用 2、8、16進制表示。
因此,計算機表示浮點數的公式如下
S 表示正負,S = 0時,N為正數,S = 1 時, N為負數。
m 為小數尾數。
Rm 表示階碼的基。
e 表示階碼的值。
浮點數在數據存儲單元中的存儲方式如圖
有些書籍和教程中, 將 er 和 e 位放到一起
浮點數的階碼需要移碼。
出現上面的原理,只是將屬於尾數的符號位(正負)放到了開頭的位置。
原碼:二進制數的最高一位代表正負符號,0代表正號,1代表負號,以下各位給出數值絕對值的表示法。
原理:(-1)S ,當 s = 0
時,值為正數;當 s = 1
時,值為負數。
零有正零和負零兩種表示形式。
補碼:將一個數轉為原碼后。
若為正數,數的補碼和原碼相同,不需要變換。
若為負數,除首位外,其余位取反,最后一位加 1。
零只有一種表示形式,即原碼中的正零。
移碼:移碼(又叫增碼)是符號位取反的補碼,一般用指數的移碼減去1來做浮點數,引入的目的是為了保證浮點數的機器碼為全0。
移碼與補碼的符號位互為相反數。
例如將一個數 666666 轉為 8 進制浮點數格式
666666(int) = 2426052 = 2.426052 * 8^6
以上可知,m = 0.2426052;rm = 8;e = 6;
八進制 2426052 的二進制為 00001010 00101100 00101010
6 的二進制 00000110;移碼為 10000110。
合並起來就是 10000110 + 00001010 00101100 00101010
所以 666666 存儲形式為 0100001100001010 00101100 00101010
要注意的是,實際計算是二進制的,上面的計算方法只是為了更加清晰理解表示方法。
可以看到,當位數一定時,階碼的位數越大,可以表示的范圍越大,但是精度變低;
階碼的位數越小,可以表示的范圍越小,但是精度更高。
浮點數標准
IEEE754 中,規定了單精確度(float)、雙精確度(double) 兩種基本浮點型
Float
那么階碼的值e 最大為 28-1 ,-127~128 (因為負數需要補碼+1)。
rme = 2-127 ~ 2128
2128 是 rme 的最大絕對值。
所以上下限范圍是 -3.4028236692094e+38 ~ 3.4028236692094e+38
。
去除多余的小數,為 -3.40E+38 ~ +3.40E+38
。
尾數范圍 223 = 8388608,一共7位。
所以 Float 精確度只有 7 位。因為往往最后一位是四舍五入后的數,所以能完全保證准確度的只有 6 位。
例題
1,求 -666666 在 float 中存儲的形式
解題過程:
將 -666666 轉為 二進制 為 10001010 00101100 00101010
。因為負數需要補碼,
所以 反碼11110101 11010011 11010101
,補碼 11110101 11010011 11010110 。
回歸正題,
-666666 = -11110101 11010011 11010110,
移動5位 = -1.1110101 11010011 11010110 * 223
e = 23,轉為 二進制為存儲數 0001 0111,移碼 1001 0111。
最后 1 1001 0111 1110101 11010011 11010110 。
2,求 -6.66666 在 float 中存儲的形式
將 6 轉為二進制為 0000 0110
0.66666 轉為二進制為 0.10101010101010100011101011010001100011010010010111111... ...
因為留給存儲尾數的空間只有 24 位,6已經使用了一位,所以
0.66666 取16 位為 0.1010101010101010,其余精度丟失。
6.66666 轉為二進制為 0000 0110 . 10101010 10101010
倒過來 110.1010101010101010 轉為 10 進制為 6.666656494140625
,精度發生變化。
-6.66666 原碼 1000 0110 . 10101010 10101010
補碼 1111 1001 . 01010101 01010111
小數點左移 7 位 1.111 1001 01010101 01010111
所以 6.66666 = 1.111 1001 01010101 01010111 * 27
7 轉為二進制為 0000 0111,移碼為 1000 0111
最后 1 1000 0111 111 1001 01010101 01010111
可以看到,上面已經發生精度丟失了。