IEEE 754浮點數表示標准


二進制數的科學計數法

C++中使用的浮點數包括采用的是IEEE標准下的浮點數表示方法。我們知道在數學中可以將任何十進制的數寫成以10為底的科學計數法的形式,如下

其中顯而易見,因為如果a比10大或者比1小都能夠再次寫成10的指數的形式,如

然而要想在二進制的世界中將數字寫成以10為底的科學計數法的形式,着實有點麻煩,因為你首先需要將二進制的數先化成10進制的表示方法,然后才能寫成科學計數法的形式。但是如果我們稍微變通一下科學計數法的標記方法,問題就變得特別的簡單了。之所以數學上使用的科學計數法選用10為底,是因為我們通常使用的計數方式是十進制的。在計算機的世界中我們使用的數卻是二進制的,所以我們在這個世界中應該改用以2為底的科學計數法而不是10為底的科學計數法。此時我們使用的科學計數法就表示成了如下形式,

對於一個二進制的數來說是不言而喻的,以為例

IEEE 754標准下的存儲策略

IEEE標准下的浮點數存儲包括三個基本的組成:符號位、指數、尾數(the sign, the exponent, the mantissa),尾數是由小數部分和一個隱含的前導數位組成。至於前導數位隱含的原因很簡單(下面將會解釋)。

下面的表格展示了計算機存儲單精度和雙精度浮點數的層次結構,包括每一部分的比特位(比特范圍用方括號括出,00表示最低位)

Floating Point Components
  Sign Exponent Fraction
Single Precision 1 [31] 8 [30-23] 23 [22-00]
Double Precision 1 [63] 11 [62-52] 52 [51-00]
  • 符號位

符號位非常簡單,位於存儲浮點數的最高比特位,且只占1比特。0表示正數,1表示負數。通過改變該比特位的值可以改變該浮點數的符號。

  • 指數位

因為指數位既需要能夠表示正指數也需要能夠表示負指數,為了能夠做到這一點,需要將真實的指數數值加上一個偏移值獲得用來存儲的指數值。對於IEEE標准下的單精度浮點數,這個偏移值是127。因此當真實的指數為0的時候,我們存儲的指數位為127。如果存儲的指數值是200,那么真實的指數值就應該是(200-127),即73。后面的原因會指出,指數為-127(指數位全為0)和+128(指數位全為1)會被用來存儲特殊的數值。

對於雙精度的浮點數,指數位的長度位11比特,偏移量位1023。

  • 尾數

尾數也被稱為有效數位(significand),決定浮點數的精確度。它由隱含的前導數位(小數點左邊的部分)和小數部分(小數點右邊的部分)組成,因為我們采用以2為底的科學計數法表示二進制數,那么小數點左邊的尾數部分自然是固定值1(),所以前導數位我們不需要明確的表示出來,我們只需要存儲尾數的小數部分就可以了。

浮點數存儲示例

下面就以單精度浮點數來浮點數的存儲策略。

十進制數0.1562510 寫成二進制的形式為0.001012。通過乘以以2為底的指數,將小數點向右移動3位后得到

這個時候我們就能夠確定它的尾數的小數部分和指數分別是多少了,尾數的小數部分位.012,指數為-3。具體存儲方法見下圖,

在IEEE 745標准下,我們用三部分來表示一個浮點數:

  • sign = 0, 因為該浮點數為正數(用1表示負數);
  • 真實的指數是-3,但是我們用來存儲的指數要在真實的指數上加上偏移量。在單精度浮點數中,這個偏移量是127,在雙精度浮點數中這個偏移量是1023;所以我們這里用來存儲的指數應該為(-3+127),即124。

浮點數的范圍

我們先來考慮單精度浮點數的范圍問題。注意到我們用來存儲雙精度浮點數的是一塊長為32bits的內存,我們重新解釋了一下該快內存中數字的存儲規則使得表示數的范圍大大增加。但是我們看看這樣子帶來了什么問題?

對於32bits的無符號整數來說,它可以表示0~232-1范圍內的任意整數。但是單精度的浮點數卻做不到這一點,因為浮點數的存儲策略中用來存儲尾數的長度只有24bits,這個時候單精度浮點數就會把將底位的部分截斷,例如

11110000 11001100 10101010 10101111  // 32-bit integer
= +1.1110000 11001100 10101011 x 2^31     // Single-Precision Float
=   11110000 11001100 10101011 00000000  // Corresponding Value

 這樣的方法可以近似32bits的值,但是並不能得到准確的結果。忽略精確度的問題,浮點數能夠表示的范圍是2127,而32bits整數的表示范圍是232

特殊值

按照上面的浮點數表示方法,我們發現並不能表示出數值0的大小。因為我們認為前導數位的值永遠為0,這個時候無論尾數的小數部分和指數部分怎么取,浮點數的值都不會是0。為此我們規定,當指數位全部為0且尾數的小數位全為0時,這個時候浮點數的值為0。注意,+0和-0時兩個不同的浮點數,即使他們的數值一樣,但是浮點數的表示方式不一樣。

  • 非標准化的值

當指數部分全為0,但時小數位不全為0的時候,這個時候浮點數表示的值就是非標准化的值。這個時候我們認為該浮點數的前導數位為0,因此這個時候的單精度浮點數大小為(−1)s × 0.f × 2−126,雙精度浮點數的大小為(−1)s × 0.f × 2−1022,其中s為符號位上的數值,2為底的指數分別是-126和-1022,而不是-127和-1023。具體原因很簡單,因為標准化所能表示的最小值是(−1)s × 1 × 2−126和(−1)s × 1× 2−1022。提出非標准化的目的就是為了表示更小的值從而提高精確度。

  • 無窮大

當指數位全為1,而尾數的小數部分全為0時表示+∞和−∞,同時通過符號位來區分+∞和−∞。所以采用IEEE 754標准表示浮點數可以很好的處理無窮大的情況。

  • 非數字(NaN)

NaN(Not a Number)用來表示非數字的值,當指數位全為1且尾數的小數部分不為0時表示NaN值。一共有兩類NaN值,靜態非數(QNaN, Quiet NaN)和警告非數(SNaN, Signalling NaN)。

在一個NaN的值中,如果尾數小數部分首位被置位則表示QNaN。QNaN是很重要的一類非數,四則運算經常傳遞QNaN值,該值通常表示不被數學上定義的運算結果,比如除數為零的時候。

在一個NaN的值中,如果尾數小數部分首位被置0則表示SNaN。它別用來表示操作中的一個異常,可以用來表示一個未被初始化變量的過早使用。

 

 Reference:

[1] http://steve.hollasch.net/cgindex/coding/ieeefloat.html

[2] https://en.wikipedia.org/wiki/IEEE_754-1985

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM