IEEE 754(IEEE754標準)

IEEE 754

IEEE754標準一般指本詞條

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”。

基本介紹

  • 中文名:IEEE二進位浮點數算術標準
  • 外文名:IEEE 754
  • 標準編號:IEEE 754-2008
  • 等價標準:ISO/IEC/IEEE 60559:2011
  • 標準名稱:IEEE浮點數算術標準
  • 制定機構:微處理器標準委員會(MSC)
浮點數剖析,本文表示比特的約定,整體呈現,浮點數的比較,浮點數的捨入,浮點數的運算與函式,精度,討論一,討論二,例子,相關條目,

浮點數剖析

一個浮點數 (Value) 的表示其實可以這樣表示:
也就是浮點數的實際值,等於符號位(sign bit)乘以指數偏移值(exponent bias)再乘以分數值(fraction)。
以下內文是IEEE 754對浮點數格式的描述。

本文表示比特的約定

把W個比特(bit)的數據,從記憶體地址低端到高端,以0到W−1編碼。通常將記憶體地址低端的比特寫在最右邊,稱作最低有效位(Least Significant Bit,LSB),代表最小的比特,改變時對整體數值影響最小的比特。聲明這一點的必要性在於X86體系架構是小端序的數據存儲。
對於十進制整數N,必要時表示為N10以與二進制的數的表示N2相區分。
對於一個數,其二進制科學計數法表示下的指數的值,下文稱之為指數的實際值;而根據IEEE 754標準對指數部分的編碼的值,稱之為浮點數表示法指數域的編碼值

整體呈現

圖1圖1
指數偏差
指數偏差(表示法中的指數為實際指數減掉某個值)為 ,其中的e為存儲指數的比特的長度。減掉一個值因為指數必須是有號數才能表達很大或很小的數值,但是有號數通常的表示法——補碼(two's complement),將會使比較變得困難。為了解決這個問題,指數在存儲之前需要做偏差修正,將它的值調整到一個無符號數的範圍內以便進行比較。此外,指數採用這種方法表示的優點還在於使得浮點數的正規形式和非正規形式之間有了一個平滑的轉變。指數偏差
圖2圖2
指數偏移值
指數偏移值(exponent bias),是指浮點數表示法中的指數域的編碼值為指數的實際值加上某個固定的值,IEEE 754標準規定該固定值為
,其中的
為存儲指數的比特的長度。
以單精度浮點數為例,它的指數域是8個比特,固定偏移值是
。此為有號數的表示方式,單精度浮點數的指數部分實際取值是從-128到127。例如指數實際值為
,在單精度浮點數中的指數域編碼值為
,即
採用指數的實際值加上固定的偏移值的辦法表示浮點數的指數,好處是可以用長度為
個比特的無符號整數來表示所有的指數取值,這使得兩個浮點數的指數大小的比較更為容易,實際上可以按照字典序比較兩個浮點表示的大小。
這種移碼表示的指數部分,中文稱作階碼
規約形式的浮點數
如果浮點數中指數部分的編碼值在
之間,且在科學表示法的表示方式下,分數 (fraction) 部分最高有效位(即整數字)是1,那么這個浮點數將被稱為規約形式的浮點數。“規約”是指用唯一確定的浮點形式去表示一個值。
由於這種表示下的尾數有一位隱含的二進制有效數字,為了與二進制科學計數法的尾數(mantissa)相區別,IEEE754稱之為有效數(significant)。
舉例來說,雙精度 (64-bit) 的規約形式浮點數在指數偏移值的值域為
(11-bit) 到
,在分數部分則是
(52-bit)。
非規約形式的浮點數
如果浮點數的指數部分的編碼值是0,分數部分非零,那么這個浮點數將被稱為非規約形式的浮點數。一般是某個數字相當接近零時才會使用非規約型式來表示。 IEEE 754標準規定:非規約形式的浮點數的指數偏移值比規約形式的浮點數的指數偏移值小1。例如,最小的規約形式的單精度浮點數的指數部分編碼值為1,指數的實際值為-126;而非規約的單精度浮點數的指數域編碼值為0,對應的指數實際值也是-126而不是-127。實際上非規約形式的浮點數仍然是有效可以使用的,只是它們的絕對值已經小於所有的規約浮點數的絕對值;即所有的非規約浮點數比規約浮點數更接近0。規約浮點數的尾數大於等於1且小於2,而非規約浮點數的尾數小於1且大於0。
除了規約浮點數,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(和符號位相關)
如果指數=
並且尾數的小數部分是0,這個數是±(同樣和符號位相關)
如果指數=
並且尾數的小數部分非0,這個數表示為不是一個數(NaN)。
以上規則,總結如下:
形式指數小數部分
0
0
非規約形式
0
非0
規約形式
1到
任意
無窮
0
NaN
非零
32位單精度
單精度二進制小數,使用32個比特存儲。
1
8
23位長
S
Exp
Fraction
31
30至23
偏正值(實際的指數大小+127)
22至0位編號(從右邊開始為0)
S為符號位,Exp為指數字,Fraction為有效數字。 指數部分即使用所謂的偏正值形式表示,偏正值為實際的指數大小與一個固定值(32位的情況是127)的和。採用這種方式表示的目的是簡化比較。因為,指數的值可能為正也可能為負,如果採用補碼錶示的話,全體符號位S和Exp自身的符號位將導致不能簡單的進行大小比較。正因為如此,指數部分通常採用一個無符號的正數值存儲。單精度的指數部分是−126~+127加上偏移值127,指數值的大小從1~254(0和255是特殊值)。浮點小數計算時,指數值減去偏正值將是實際的指數大小。
單精度浮點數各種極值情況:
類別正負號實際指數有偏移指數指數域尾數域數值
0
-127
0
0000 0000
000 0000 0000 0000 0000 0000
0.0
負零
1
-127
0
0000 0000
000 0000 0000 0000 0000 0000
−0.0
1
0
0
127
0111 1111
000 0000 0000 0000 0000 0000
1.0
-1
1
0
127
0111 1111
000 0000 0000 0000 0000 0000
−1.0
最小的非規約數
*
-126
0
0000 0000
000 0000 0000 0000 0000 0001
±2× 2= ±2≈ ±1.4×10
中間大小的非規約數
*
-126
0
0000 0000
100 0000 0000 0000 0000 0000
±2× 2= ±2≈ ±5.88×10
最大的非規約數
*
-126
0
0000 0000
111 1111 1111 1111 1111 1111
±(1−2) × 2≈ ±1.18×10
最小的規約數
*
-126
1
0000 0001
000 0000 0000 0000 0000 0000
±2≈ ±1.18×10
最大的規約數
*
127
254
1111 1110
111 1111 1111 1111 1111 1111
±(2−2) × 2≈ ±3.4×10
正無窮
0
128
255
1111 1111
000 0000 0000 0000 0000 0000
+∞
負無窮
1
128
255
1111 1111
000 0000 0000 0000 0000 0000
−∞
*
128
255
1111 1111
non zero
NaN
* 符號位可以為0或1.
64位雙精度
雙精度二進制小數,使用64個比特存儲。
1
11
52位長
S
Exp
Fraction
63
62至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的方向捨入。

浮點數的運算與函式

標準運算
下述函式必須提供:
加減乘除(Add、subtract、multiply、divide)。在加減運算中負零與零相等:
平方根(Square root):
,另規定
浮點餘數。返回值
近似到最近的整數
。如果恰好在兩個相鄰整數之間,則近似到偶數。
比較運算. -Inf <負的規約浮點數數<負的非規約浮點數< -0.0 = 0.0 <正的非規約浮點數<正的規約浮點數< Inf;
特殊比較: -Inf = -Inf, Inf = Inf, NaN與任何浮點數(包括自身)的比較結果都為假,即 (NaN ≠ x) = false.

精度

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

討論一

單精和雙精浮點數的有效數字分別是有存儲的23和52個位,加上最左手邊沒有存儲的第1個位,即是24和53個位。
由以上的計算,單精和雙精浮點數可以保證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++程式,概略地展示了單精和雙精浮點數的精度。
#include <iostream>int main () {    std::cout.precision(20);    float a=123.45678901234567890;    double b=123.45678901234567890;    std::cout << a << std::endl;    std::cout << b << std::endl;    return 0;}// Xcode 5.1// Output:// 123.456787109375// 123.45678901234568059// Program ended with exit code: 0

相關條目

相關詞條

熱門詞條

聯絡我們