IEEE 742標准規定了一個浮點數表示公式:V = (-1)^s * M * 2^E
-
怎么理解這個公式?
其實這里有一個知識點:浮點數是用科學計數法來表示的。
比如十進制數25.125
25.125_{(D)} = 11001.001_{B} = 1.1001001 * 2^4
你也可以把它表示成0.11001001 * 2^5,11.001001 * 2^3, 110.01001 * 2^2,11100100.1 * 2^{-3}等等,實際上浮點數的得名也是源自於它的點位漂浮不定的情況,在實際應用中我們采用IEEE 標准,用科學計數法統一表示這些浮點數。
回頭看公式,其中V(Value)表示浮點數的十進制值;
S(Sign)符號位表示浮點數的正符號,取1為負,0為正;上例顯然是正數, S = 0。
注意,面對這個符號位要擺脫之前整數補碼取反加1求負的思想,實際上求浮點數的負值只要偏轉一個符號位就行了。
M(Mantissa)表示尾數,表示 二進制浮點數 科學計數法表示形式 下的小數部分; 上例中M = 1.1001001
E (Exponent) 表示階碼,是一個有符號數,表示 二進制浮點數 科學計數法表示形式 的2次冪的值,上例中 E = 4
-
怎么把數裝進計算機的二進制位?
IEEE 提供了浮點數的32位和64位表示形式:
這里除了符號位外又看到兩個變量exp 和 frac 。
這兩個參數的作用是什么?這里又要開始講IEEE標准,制定IEEE標准的這幫人根據exp的值分了三類情況:規格化,非規格化,特殊值情況,我們先主講規格化的情況。
-
規格化
即exp的位模式既不全為0也不全為1的情況,該情況下IEEE二進制數對應到科學計數法表示要通過如下公式:
E = exp - bias
M = 1 + frac
exp是exponent,即指數,注意別和階碼E混淆,exp是一個無符號整數,而E是有符號整數;
frac是fraction, 即M去掉整數部分后的小數字段, 注意規格化表示下尾數的第一位一定是1,正如科學計數法下非0數表示的第一位一定非0的情況。
其中bias 是一個偏置值,和之前2.3用於保證整數向0舍入的bias不一樣,這個bias是用於浮點數計算時能對齊兩數的階碼使用的。這一部分我並不是了解的很清楚,目前要記住E是一個移碼,參考:
bias 的取值是 bias = 2^{n-1} - 1 ,其中 n 是exp的數據位數,單精度下bias 值為
127
(n = 8), 雙精度下為1023
(n = 11)。單精度情況下,階碼E的有符號表示范圍為
-127 ~ +128
,但是-127 和 128 在規格化里是沒被用來表示的,原因是在IEEE標准中這兩個數分別被用來規定了非規格化和特殊值的情況,也即單精度的規格化階碼exp范圍是 00000001(-126)-11111110(127) , 之后討論。注意,看exp不能按正常的二進制轉十進制的思維轉成十進制,需要減去偏差。
單精度情況exp和E對照:
exp(B) exp(D) E 0000 0000 (非規格化) 0 -126(非規格化情況E = 1 - bias) 0000 0001 1 -126 … 1111 1110 254 127 1111 1111 (特殊值) 255 -- 規格化情況的公式變為:
V = \begin{cases} (-1)^s * (1 + frac)*2^{exp - 127},float\\\ (-1)^s * (1 + frac)*2^{exp - 1023},double\end{cases}
按照規格表示,我們得到了25.125D(即1.1001001 * 2^4)的單精度表示方法:
1_{(s,1位)} 10000011_{(exp,8位)} 10010010000000000000000_{(fra,23位)}
注意,在實際的位表示中開頭1被省略掉了(即implied leading 1, 隱含的1開頭表示),用以獲得一個額外的尾數位以提高精度。
-
非規格化
階碼域全為0時,表示的值就是非規格化的,非規格數可以用來表示0及其他一些非常小的數,注意+0.0和-0.0在浮點數中是同時存在的,僅有符號位的不同。非規格化中M和E的公式定義為:
M = frac
E = 1- bias
非規格化的尾數是0開頭的,故M代表的就是小數部分,至於E 為什么等於 1-bias會比較費解,其實這里的1是對非規格化數沒有隱含的1的補償,其有益於最大非規格化數到最小規格化數的平滑轉變。
另外,值比較小的規格化的數在更低位數的機器中可能成為非規格化數。我們知道,增大尾數位有益於提高浮點數的表示精度從而得到更大的規格化值,而增大指數為有益於提高浮點數的表示范圍得到更小更精確的規格化值,我們可以試想下列情況:
設階碼位為k, 尾數位為n,偏置量bias
32位環境下的某小數0.001953的二進制表示形式為:
0_{(s,1位)}01110101_{(exp,8位)} 11111111111101111001110_{(fra,32位)}
其計數表示為1.1111111111110111100111 * 2^{-10}
放到k = 4,n = 3,bias = 7的機器環境中表示為:
0_{(s,1位)}0000_{(exp,4位)} 001_{(fra,3位)}
E = 1 - 7 = -6, M = 0.001 ,故0.001953在該環境下表示為0.001* 2^{-6}
(0.000000001_{B},顯然是1/512的近似結果,具體看CSAPP圖2-35參考),
若要讓小數點到達1前,階碼值需要到-9,即規格化表示是1.0 * 2^{-9},可是該環境下的階碼E范圍為 -6 ~ 7,顯然超出了取值范圍,E取最小值也無法滿足開頭是1的規格化條件,只能表示成非規格形式。
另外可見,如果表示的浮點數的計數表示超過了E的最大范圍,就會導致溢出,值變為+\infty。比如上述環境中256.0的計數表示為 1.0* 2^8, 用4個指數位已經不夠表示了(E = 14(1110) - 7 = 7 < 8(1111)),於是全1溢出。
-
特殊值
特殊值包括正無窮,負無窮和NaN(即不是一個數,Not a Number), 在階碼全為1的時候出現,其中當小數位全為0時,s=1表示負無窮,s=0表示正無窮,如果小數位不全為數就是NaN, 它們的用處是用於表示未初始化的數據,比較少見,這里不再詳談。
參考:
http://kaito-kidd.com/2018/08/08/computer-system-float-point/
-
-