IEEE 754 理解記錄


IEEE 754 是最廣泛使用的 二進制浮點數算術標准。

組成

浮點法表示一個數分為三個部分:符號位 + 指數 + 尾數;通常我們是用二進制的科學計數法表示出來,如 5(101) 記成 \(1.01 * 2^2\)。我們可以稱 01 為尾數,2為指數。

IEEE754的表示也分為三個部分:

  • 符號位 sign

    符號位只占一位,0表示正數,1表示負數

  • 階碼 exponent

    也就是指數,不過又與指數在數值表示上不同,階碼進行了偏移。為了與實際的指數進行區分,后續我們都稱為“階碼”而不是指數。

    階碼有 e 位,在指數的基礎上偏移了 \(2^{e-1}-1\)

    為什么要偏移呢?因為0次方是存在的,但階碼的0要用於表示特殊的數(零或非規格數),因此需要找其他的數代替0。

    以單精度的舉例,階碼有8位,就要偏移 127,看一個對應圖就明白了。

    image-20211020213514726

    可以看到單精度可表示的指數范圍為 -126 ~ 127。

  • 尾數 fraction

    即表示為科學計數法后的小數部分,如上面的5,尾數部分則是 01。因為二進制中第一個有效數字必定是1,因此可以節約1bit。

IEEE 754規定了四種表示浮點數值的方式:單精確度(32位)、雙精確度(64位)、延伸單精確度(43比特以上,很少使用)與延伸雙精確度(79比特以上,通常以80位實現)。其中單精度指數域有 8 個bit,尾數有 23 個bit;雙精度指數域為 11 bit,尾數為 52 bit。

意義

符號位 階碼 尾數 意義
0/1 0 0 ±零
0/1 0 非0 非規格化數
0/1 1 ~ \(2^{e-2}\) 任意 規格化數
0/1 \(2^e - 1\)(全1) 0 ±無窮
0/1 \(2^e - 1\)(全1) 非零 非數值 NaN

1、零

浮點數的0還區分正負,不過一般似乎沒有什么區別。只是在除法時有點區別:

double x = 0.0;
double y = -0.0;
1/x == INF; 1/y == -INF;

2、規格化數

規格化的意思是采用科學計數法的規范表示的數。

如單精度的規格化數范圍為:

\[±(1.xx···xx × 2^{-126} , 1.xx···xx × 2^{127}) \]

其中x為0或1。

3、非規格化數

非規格化可以用於表示比規格化數還接近0的數。

非規約形式的浮點數的指數偏移值比規約形式的浮點數的指數偏移值小1。例如,最小的規格單精度浮點數的階碼為1,指數的實際值為-126;而非規格單精度浮點數的階碼為0,對應的指數實際值也是-126而不是-127。

非規約浮點數源於70年代末IEEE浮點數標准化專業技術委員會醞釀浮點數二進制標准時,Intel公司對漸進式下溢出(gradual underflow)的力薦。當時十分流行的DEC VAX機的浮點數表示采用了突然式下溢出(abrupt underflow)。

如果沒有漸進式下溢出,那么0與絕對值最小的浮點數之間的距離將大於相鄰的小浮點數之間的距離。例如單精度浮點數的絕對值最小的規約浮點數是1.0*2-126,它與絕對值次小的規約浮點數之間的距離為2-126 * 2-23;如果不采用漸進式下溢出,那么絕對值最小的規約浮點數與0的距離是相鄰的小浮點數之間距離的223倍,可以說是非常突然的下溢出到0。這種情況的一種糟糕后果是:兩個不等的小浮點數X與Y相減,結果將是0。這對於普通的程序員會很容易陷入迷惑,采用了漸進式下溢出后將不會出現這種情況,也就是采用非規約數表示更接近0的數。采用了非規約數后,0與最近的浮點數(最小的非規約數)的距離也是 2-126 * 2-23

4、無窮

INF表示無窮,出現無窮的常見情況有:

  • 無窮與自身運算, 如負無窮+2依然是負無窮
  • 被0除, 例如1/0得到正無窮
  • 上溢, 即計算結果超出類型范圍

5、非數值

即一些運算過程中出現的非數值情況。NaN還分為兩類:

  • QNAN,尾數部分最高位為1,一般表示未定義的算術運算結果,最常見的如除0運算;
  • SNAN,尾數最高位為0;一般被用於標記未初始化的值,以此來捕獲異常。

有趣的現象

連續和不連續

雖然浮點數可以表示很大的數,但是它只在中間部分是連續的,過大的數是不連續的,間隔很大,因為指數很大但尾數的個數是很有限的。而特別小的數因為有非規約數,所以還比較連續。

js最大安全數

JavaScript中的數值統一都是雙精度浮點數,js存在一個最大的安全數,為253-1,當我們們表示整數的時候,指數部分為1,只通過尾數表示。因為如果用到高次的階碼,那么大數就不是遞增1的了,這在程序中容易出錯。

而為什么是253-1呢,因為雙精度的尾數有52位,這里省去了第一位有效數字,所以能表示的應該是53位,因此最大的數就是253-1。

前后端開發的時候,后端傳給前端的整數值不能過大,否則會出現部分位丟失的問題。我在個人博客項目中,表的分布式id為64位long型,傳給前端就會出現截斷丟失。


免責聲明!

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



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