IEEE 754

IEEE 754

IEEE二進制浮點數算術標準(IEEE 754)是20世紀80年代以來最廣泛使用的浮點數運算標準,為許多CPU與浮點運算器所採用。這個標準定義了表示浮點數的格式(包括負零-0)與反常值(denormal number)),一些特殊數值(無窮(Inf)與非數值(NaN)),以及這些數值的“浮點數運算符”;它也指明了四種數值捨入規則和五種例外狀況(包括例外發生的時機與處理方式)。 IEEE 754規定了四種表示浮點數值的方式:單精確度(32位)、雙精確度(64位)、延伸單精確度(43比特以上,很少使用)與延伸雙精確度(79比特以上,通常以80位實現)。只有32位模式有強制要求,其他都是選擇性的。大部分程式語言都有提供IEEE浮點數格式與算術,但有些將其列為非必需的。例如,IEEE 754問世之前就有的C語言,現在有包括IEEE算術,但不算作強制要求(C語言的float通常是指IEEE單精確度,而double是指雙精確度)。 該標準的全稱為IEEE二進制浮點數算術標準(ANSI/IEEE Std 754-1985),又稱IEC 60559:1989,微處理器系統的二進制浮點數算術(本來的編號是IEC 559:1989)。後來還有“與基數無關的浮點數”的“IEEE 854-1987標準”,有規定基數為2跟10的狀況。現在最新標準是“ISO/IEC/IEEE FDIS 60559:2010”。

浮點數剖析

一個浮點數 (Value) 的表示其實可以這樣表示:

IEEE 754 IEEE 754

也就是浮點數的 實際值,等於符號位(sign bit)乘以 指數偏移值(exponent bias)再乘以 分數值(fraction)。

以下內文是IEEE 754對浮點數格式的描述。

本文表示比特的約定

把W個比特(bit)的數據,從記憶體地址低端到高端,以0到W−1編碼。通常將記憶體地址低端的比特寫在最右邊,稱作最低有效位(Least Significant Bit,LSB),代表最小的比特,改變時對整體數值影響最小的比特。聲明這一點的必要性在於X86體系架構是小端序的數據存儲。

對於十進制整數N,必要時表示為N以與二進制的數的表示N相區分。

對於一個數,其二進制科學計數法表示下的指數的值,下文稱之為 指數的實際值;而根據IEEE 754標準對指數部分的編碼的值,稱之為浮點數表示法 指數域的編碼值

整體呈現

圖1 圖1

指數偏差

指數偏差(表示法中的指數為實際指數減掉某個值)為 ,其中的e為存儲指數的比特的長度。減掉一個值因為指數必須是有號數才能表達很大或很小的數值,但是有號數通常的表示法——補碼(two's complement),將會使比較變得困難。為了解決這個問題,指數在存儲之前需要做偏差修正,將它的值調整到一個無符號數的範圍內以便進行比較。此外,指數採用這種方法表示的優點還在於使得浮點數的正規形式和非正規形式之間有了一個平滑的轉變。指數偏差

圖2 圖2

指數偏移值

IEEE 754 IEEE 754
IEEE 754 IEEE 754

指數偏移值(exponent bias),是指浮點數表示法中的指數域的編碼值為指數的實際值加上某個固定的值,IEEE 754標準規定該固定值為 ,其中的 為存儲指數的比特的長度。

IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754

以單精度浮點數為例,它的指數域是8個比特,固定偏移值是 。此為有號數的表示方式,單精度浮點數的指數部分實際取值是從-128到127。例如指數實際值為 ,在單精度浮點數中的指數域編碼值為 ,即 。

IEEE 754 IEEE 754

採用指數的實際值加上固定的偏移值的辦法表示浮點數的指數,好處是可以用長度為 個比特的無符號整數來表示所有的指數取值,這使得兩個浮點數的指數大小的比較更為容易,實際上可以按照字典序比較兩個浮點表示的大小。

這種 移碼表示的指數部分,中文稱作 階碼

規約形式的浮點數

IEEE 754 IEEE 754

如果浮點數中指數部分的編碼值在 之間,且在 科學表示法的表示方式下,分數 (fraction) 部分 最高有效位(即整數字)是1,那么這個浮點數將被稱為 規約形式的浮點數。“規約”是指用唯一確定的浮點形式去表示一個值。

由於這種表示下的尾數有一位隱含的二進制有效數字,為了與二進制科學計數法的尾數(mantissa)相區別,IEEE754稱之為 有效數(significant)。

IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754

舉例來說,雙精度 (64-bit) 的規約形式浮點數在指數偏移值的值域為 (11-bit) 到 ,在分數部分則是 到 (52-bit)。

非規約形式的浮點數

如果浮點數的指數部分的編碼值是0,分數部分非零,那么這個浮點數將被稱為 非規約形式的浮點數。一般是某個數字 相當接近零時才會使用非規約型式來表示。 IEEE 754標準規定: 非規約形式的浮點數的指數偏移值比規約形式的浮點數的指數偏移值小1。例如,最小的規約形式的單精度浮點數的指數部分編碼值為1,指數的實際值為-126;而非規約的單精度浮點數的指數域編碼值為0,對應的指數實際值也是-126而不是-127。實際上非規約形式的浮點數仍然是有效可以使用的,只是它們的絕對值已經小於所有的規約浮點數的絕對值;即所有的非規約浮點數比規約浮點數更接近0。規約浮點數的尾數大於等於1且小於2,而非規約浮點數的尾數小於1且大於0。

IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754
IEEE 754 IEEE 754

除了規約浮點數,IEEE754-1985標準採用非規約浮點數,用來解決填補絕對值意義下最小規格數與零的距離。(舉例說,正數下,最大的非規格數等於最小的規格數。而一個浮點數編碼中,如果exponent=0,且尾數部分不為零,那么就按照非規約浮點數來解析)非規約浮點數源於70年代末IEEE浮點數標準化專業技術委員會醞釀浮點數二進制標準時,Intel公司對 漸進式下溢出(gradual underflow)的力薦。當時十分流行的DECVAX機的浮點數表示採用了 突然式下溢出(abrupt underflow)。如果沒有漸進式下溢出,那么0與絕對值最小的浮點數之間的距離(gap)將大於相鄰的小浮點數之間的距離。例如單精度浮點數的絕對值最小的規約浮點數是 ,它與絕對值次小的規約浮點數之間的距離為 。如果不採用漸進式下溢出,那么絕對值最小的規約浮點數與0的距離是相鄰的小浮點數之間距離的 倍!可以說是非常突然的下溢出到0。這種情況的一種糟糕後果是:兩個不等的小浮點數X與Y相減,結果將是0.訓練有素的數值分析人員可能會適應這種限制情況,但對於普通的程式設計師就很容易陷入錯誤了。採用了漸進式下溢出後將不會出現這種情況。例如對於單精度浮點數,指數部分實際最小值是(-126),對應的尾數部分從 , 一直到 相鄰兩小浮點數之間的距離(gap)都是 ;而與0最近的浮點數(即最小的非規約數)也是 。

特殊值

這裡有三個特殊值需要指出:

如果 指數是0並且尾數的 小數部分是0,這個數±0(和符號位相關)

IEEE 754 IEEE 754

如果 指數= 並且尾數的 小數部分是0,這個數是±∞(同樣和符號位相關)

IEEE 754 IEEE 754

如果 指數= 並且尾數的 小數部分非0,這個數表示為不是一個數(NaN)。

以上規則,總結如下:

形式指數小數部分
00
非規約形式0非0
規約形式1到
IEEE 754 IEEE 754
任意
無窮
IEEE 754 IEEE 754
0
NaN
IEEE 754 IEEE 754
非零

32位單精度

單精度二進制小數,使用32個比特存儲。

1823位長
SExpFraction
3130至23
偏正值(實際的指數大小+127)
22至0位編號(從右邊開始為0)

S為符號位,Exp為指數字,Fraction為有效數字。 指數部分即使用所謂的 偏正值形式表示,偏正值為實際的指數大小與一個固定值(32位的情況是127)的和。採用這種方式表示的目的是簡化比較。因為,指數的值可能為正也可能為負,如果採用補碼錶示的話,全體符號位S和Exp自身的符號位將導致不能簡單的進行大小比較。正因為如此,指數部分通常採用一個無符號的正數值存儲。單精度的指數部分是−126~+127加上偏移值127,指數值的大小從1~254(0和255是特殊值)。浮點小數計算時,指數值減去偏正值將是實際的指數大小。

單精度浮點數各種極值情況:

類別正負號實際指數有偏移指數指數域尾數域數值
0-12700000 0000000 0000 0000 0000 0000 00000.0
負零1-12700000 0000000 0000 0000 0000 0000 0000−0.0
1001270111 1111000 0000 0000 0000 0000 00001.0
-1101270111 1111000 0000 0000 0000 0000 0000−1.0
最小的非規約數*-12600000 0000000 0000 0000 0000 0000 0001±2× 2= ±2≈ ±1.4×10
中間大小的非規約數*-12600000 0000100 0000 0000 0000 0000 0000±2× 2= ±2≈ ±5.88×10
最大的非規約數*-12600000 0000111 1111 1111 1111 1111 1111±(1−2) × 2≈ ±1.18×10
最小的規約數*-12610000 0001000 0000 0000 0000 0000 0000±2≈ ±1.18×10
最大的規約數*1272541111 1110111 1111 1111 1111 1111 1111±(2−2) × 2≈ ±3.4×10
正無窮01282551111 1111000 0000 0000 0000 0000 0000+∞
負無窮11282551111 1111000 0000 0000 0000 0000 0000−∞
NaN*1282551111 1111non zeroNaN
* 符號位可以為0或1.

64位雙精度

雙精度二進制小數,使用64個比特存儲。

11152位長
SExpFraction
6362至52
偏正值(實際的指數大小+1023)
51至0位編號(從右邊開始為0)

S為符號位,Exp為指數字,Fraction為有效數字。指數部分即使用所謂的偏正值形式表示,偏正值為實際的指數大小與一個固定值(64位的情況是1023)的和。採用這種方式表示的目的是簡化比較。因為,指數的值可能為正也可能為負,如果採用補碼錶示的話,全體符號位S和Exp自身的符號位將導致不能簡單的進行大小比較。正因為如此,指數部分通常採用一個無符號的正數值存儲。雙精度的指數部分是−1022~+1023加上1023,指數值的大小從1~2046(0(2進位全為0)和2047(2進位全為1)是特殊值)。浮點小數計算時,指數值減去偏正值將是實際的指數大小。

浮點數的比較

浮點數基本上可以按照符號位、指數域、尾數域的順序作字典比較。顯然,所有正數大於負數;正負號相同時,指數的二進制表示法更大的其浮點數值更大。

浮點數的捨入

任何有效數上的運算結果,通常都存放在較長的暫存器中,當結果被放回浮點格式時,必須將多出來的比特丟棄。 有多種方法可以用來運行捨入作業,實際上IEEE標準列出4種不同的方法:

•捨入到最接近:捨入到最接近,在一樣接近的情況下偶數優先(Ties To Even,這是默認的捨入方式):會將結果捨入為最接近且可以表示的值,但是當存在兩個數一樣接近的時候,則取其中的偶數(在二進制中式以0結尾的)。

•朝+∞方向捨入:會將結果朝正無限大的方向捨入。

•朝-∞方向捨入:會將結果朝負無限大的方向捨入。

•朝0方向捨入:會將結果朝0的方向捨入。

浮點數的運算與函式

標準運算

下述函式必須提供:

IEEE 754 IEEE 754

加減乘除(Add、subtract、multiply、divide)。在加減運算中負零與零相等:

IEEE 754 IEEE 754
IEEE 754 IEEE 754

平方根(Square root): ,另規定

IEEE 754 IEEE 754

浮點餘數。返回值 。

IEEE 754 IEEE 754

近似到最近的整數 。如果恰好在兩個相鄰整數之間,則近似到偶數。

比較運算. -Inf <負的規約浮點數數<負的非規約浮點數< -0.0 = 0.0 <正的非規約浮點數<正的規約浮點數< Inf;

特殊比較: -Inf = -Inf, Inf = Inf, NaN與任何浮點數(包括自身)的比較結果都為假,即 (NaN ≠ x) = false.

精度

在二進制,第一個有效數字必定是“1”,因此這個“1”並不會存儲。

討論一

單精和雙精浮點數的有效數字分別是有存儲的23和52個位,加上最左手邊沒有存儲的第1個位,即是24和53個位。

IEEE 754 IEEE 754
IEEE 754 IEEE 754

由以上的計算,單精和雙精浮點數可以保證7位和15位十進制有效數字。

討論二

C++語言標準定義的浮點數的 十進制精度(decimal precision):十進制數字的位數,可被(浮點數)表示而值不發生變化。C語言標準定義的浮點數的十進制精度為:十進制數字的位數q,使得任何具有q位十進制數字的浮點數可近似表示為b進制的p位數字並且能近似回十進制表示而不改變這q位十進制數字

但由於相對近似誤差不均勻,有的7位十進制浮點數不能保證近似轉化為32比特浮點再近似轉化回7位十進制浮點後保持值不變:例如8.589973e9將變成8.589974e9。這種近似誤差不會超過1比特的表示能力,因此(24-1)*std::log10(2)等於6.92,下取整為6,成為std::numeric_limits<float>::digits10以及FLT_DIG的值。std::numeric_limits<float>::max_digits10的值為9,含義是必須9位十進制數字才能區分float的所有值;也即float的最大表示區分度。

類似的,std::numeric_limits<double>::digits10或DBL_DIG是15,

std::numeric_limits<double>::max_digits10是17

例子

以下的C++程式,概略地展示了單精和雙精浮點數的精度。

相關條目

•浮點數

•單精度浮點數

•雙精度浮點數

相關詞條

相關搜尋

熱門詞條

聯絡我們