浮點數格式
學C的時候就知道,浮點數采用的是類似於科學計數法的表示方式。具體的浮點數的模型是:
一個尾數(mantissa),一個基數(base),一個指數(exponent)和符號位表示。
再百度的深一點,在規范化形式下(沒錯,還有非規范形式),就可以把float和double的表示格式列個表格:
類型 |
存儲位數 |
偏移值 |
||||
|
符號位(s) |
指數位(e) |
尾數位(m) |
總位數 |
十六進制 |
十進制 |
單精度 float |
1位 |
8位 |
23位 |
32位 |
0x7FH |
+127 |
雙精度 double |
1位 |
11 位 |
52位 |
64位 |
0x3FFH |
+1023 |
不過有些細節是不得不說的:
基數 ———— 這個基數是可以用戶定義的,一般是2,但取10,16也是可以的。如何指定呢?
在頭文件float.h中定義了宏FLT—RADIX,它的值就是選定的基數。
尾數 ———— 這是個定點小數,采用原碼存儲。尾數的最左端隱含了1,也就是說23位全部用來表示小數,而實際表示的數是24位精度。
指數 ———— 這當然是整數,不過采用移碼存儲。為了處理負指數的情況,要把實際指數值加上一個偏移值作為保存值(float為127;double為1023)。對單精度浮點而言,有效的指數范圍是 -126~127(保存值為1~254,這是因為兩個端點值用作特殊值表示)。
IEEE 754定義了什么
只要一說到浮點數,這個標准是不能不提的。那么這個標准主要規定了哪些東西呢?
A、浮點數的格式:
除了上面提到的兩種基本的浮點格式,還定義了這兩種格式的擴展。
但標准只規定擴展格式的最小精度和大小。例如,IEEE 雙精度擴展格式必須至少具
有64位有效數字,並總共占用至少79 位。
B、4種浮點數舍入方式:
-
舍入到最接近:將結果舍入為最接近且可以表示的值(默認)。這種方式下,采取的向偶數舍入,
與我們熟悉的'四舍五入'不同。這主要是為了處理中值(兩個相鄰整數的平均值),如果這些值都遵循'五入',
那么在數值計算中會累積較大誤差。也就是說——— 0.5要舍到0,1.5要入到2 ———以保證50%的概率。
-
朝+∞方向舍入:將結果朝正無限大(向上)的方向舍入。
-
朝-∞方向舍入:將結果朝負無限大(向下)的方向舍入。
-
朝0方向舍入:將結果朝0的方向舍入。忽略小數部分。
這些舍入方式是可以由float.h中的宏FLT—ROUNDS指定的。
C、5種浮點異常:
-
無效運算: 默認返回NaN(如對負數開平方時)
-
被零除: 默認返回負無窮或正無窮
-
上溢: 默認返回正負無窮大(結果數據太大無法表示時)
-
下溢: 默認返回非規范數(結果數據太小無法表示時)
-
不准確: 默認返回舍入后的正確值
如果產生異常,就會影響異常向量表,有些還會產生中斷。至於中斷,異常處理當然不是本文要討論的。
D、特殊值:(還記得指數部分沒有用到的兩個端點值么?)
-
NaN(Not a Number):對於單精度浮點數,NaN 表示為指數為128(保存值=255),且尾數不等於零的浮點數。
-
± ∞: 這個數的定義和NaN一樣,不過它的尾數一定為0.(用於大出范圍的數)
-
± 0: 對單精度而言,0表示為指數域為-127(保存值=0),尾數域為全為0。
-
非規范化數: 這個數的定義和有符號0一樣,不過尾數不能為0.(用於小出范圍的數)
這個標准規范的東西當然不止這些,還有一些關於運算准確度要求、不同類型數據間轉換及不同進制數據間的轉換等等。
其實這里談到的是浮點數最老的標准,新標准應該也有幾個了吧,最好的資料當然就是這些標准的文檔,倘若有時間,仔細看看還是有好處的。
庫文件float.h
最初很多處理器在硬件方面並不支持浮點運算,因為這會增加不少成本,不支持浮點運算,會使微處理器設計的復雜度減半。之所以需要浮點運算,是因為科學計算等一些高精度運算的需要的存在。float.h這個文件的構造當然是要遵循這個標准的,不過這個頭文件並有太多的東西。除了前面提到過的兩個宏,這個頭文件還定義了一些關於浮點數取值范圍的宏。
其實也沒有特別的理由要來認識這個庫,畢竟即使是做數值計算的算法,也可以用MATLAB 這個彪悍的工具。不過,在了解了這個頭文件后,約定整數范圍的limits.h就很容易看清楚了。不過這也僅限於認識這個庫,至於它要怎么實現就又是另一個層次的問題了。
參考文章:定點數與浮點數的區別。(文章不錯,雖然有些小錯誤)