IEEE 754 浮點數位模式視覺化工具

將十進位制小數分解為IEEE 754單精度(32位)或雙精度(64位)的位模式並可視化展示,也可將位模式反向解碼為十進位制值。符號位、指數部、尾數部分色顯示,並支援識別NaN、無窮大與非規格化數。

經典案例:為什麼 0.1 + 0.2 不等於 0.3

在JavaScript中計算 `0.1 + 0.2` 得到的是 `0.30000000000000004`,而非 `0.3`。檢視雙精度的位模式即可理解原因。

數值 雙精度(64位)十六進位制 雙精度(64位)二進位制
0.1 0x3FB999999999999A 0011111110111001100110011001100110011001100110011001100110011010
0.2 0x3FC999999999999A 0011111111001001100110011001100110011001100110011001100110011010
0.3 0x3FD3333333333333 0011111111010011001100110011001100110011001100110011001100110011
0.1 + 0.2 0x3FD3333333333334 0011111111010011001100110011001100110011001100110011001100110100

0.1、0.2、0.3在二進位制中都是無限迴圈小數,無法完全放入52位的尾數部分,因此都會被四捨五入。由於0.1與0.2各自的舍入誤差方向恰好沒有抵消,兩者相加的結果與0.3的精確位模式相比只相差最後1位(0x3FD3333333333334)。可以在上方的轉換工具中親自輸入這些數值,比較末位的差異。

使用提示

  • 將0.1、0.2、0.3分別以雙精度轉換為位模式,並與0.1+0.2的結果(0.30000000000000004)對比,可以直觀地發現只有最後1位不同。
  • 在十進位制輸入框中輸入"-0",會得到只有符號位為1的位模式(與"+0"不同)。作為數值0===-0成立,但位表示本身是不同的。
  • 當指數部全為0時,尾數部為0表示零,尾數部不為0則表示非規格化數——一種以犧牲精度為代價來表示極接近零的數值的特殊表示法。
  • 將同一數值(如0.1)在單精度(32位)與雙精度(64位)之間切換,可以確認單精度的舍入誤差更大。
  • 將位模式解碼為十進位制時,需要輸入以`0x`開頭的十六進位制字串,或位數與所選精度完全一致的二進位制字串(`0b`字首可省略)。

常見問題

0.1、0.2、0.3在二進位制中都是無限迴圈小數,計算機必須將它們四捨五入以適應有限位數的尾數部(雙精度為52位)。由於0.1與0.2各自的舍入誤差方向恰好沒有相互抵消,兩者相加的結果與0.3的精確位模式略有不同(結果為0.30000000000000004)。這並非某個特定程式語言的缺陷,而是所有遵循IEEE 754標準的語言共有的現象。

單精度(float,32位)由1位符號位、8位指數部、23位尾數部組成;雙精度(double,64位)由1位符號位、11位指數部、52位尾數部組成。尾數部位數越多,有效數字(精度)越高;指數部位數越多,可表示的數值範圍越廣。大多數程式語言的浮點數預設型別都是雙精度。

指的是指數部全為0但尾數部不為0的位模式。通常的(規格化的)浮點數在尾數開頭帶有隱含的1,而非規格化數省略了這一隱含1,轉而將指數固定為最小值,從而能夠表示比通常最小值更接近零的數值,但代價是犧牲了有效精度。

IEEE 754中符號位是獨立存在的一位,因此即便指數部與尾數部都全為0,符號位為0時得到"+0",為1時得到"-0",形成兩種不同的位模式。作為數值比較時0===-0成立,但在某些運算結果中會顯現差異,例如1/0得到+Infinity,而1/-0得到-Infinity。

兩者都通過指數部全為1的位模式表示。若尾數部全為0,則表示無窮大(通過符號位區分+Infinity與-Infinity);若尾數部不為0,則表示NaN(Not a Number,非數)。它們由0除法、∞-∞等數學上未定義的運算產生。
ツールくん

閒話 ― IEEE 754如何成為一門"通用語言"

1985年以前,各計算機制造商都採用各自獨立的浮點數表示法。IBM、DEC、Cray等公司即便計算同一個"0.1",其舍入方式與可表示的數值範圍也會存在細微差異,導致在一臺機器上編寫的數值計算程式移植到另一臺機器時,結果往往會出現微小偏差。為了解決這一混亂局面,曾參與英特爾8087數值協處理器設計的加州大學伯克利分校學者William Kahan牽頭組織了跨行業的標準化工作,於1985年釋出了IEEE 754標準。

IEEE 754的核心思想,是將有限的位數(32位或64位)劃分為符號、指數部、尾數部三個部分的分工,以此近似表示無限多的實數。指數部負責數值的量級(大小規模),尾數部負責有效數字的精度,這樣即使位數有限,也能靈活覆蓋從極小到極大的數值範圍。指數部之所以要加上偏移量(單精度為127、雙精度為1023)後再儲存,是為了避免像有符號整數的補碼那樣複雜的符號處理,只需將位串作為普通整數直接比較即可判斷數值大小關係。

在二進位制中能夠被"精確"表示的小數,僅限於分母為2的冪的分數(如1/2、1/4、3/8等)。十進位制的0.1寫成分數是1/10,由於10不是2的冪,在二進位制中會變成0.0001100110011...這樣無限迴圈的小數。由於尾數部的位數有限,只能在某處截斷並四捨五入,這正是"計算機無法精確表示0.1"的根本原因。需要精確處理十進位制小數的會計系統之所以往往不使用浮點數,而改用整數運算或專門的十進位制型別(如BCD),原因也在於此。

IEEE 754此後在2008年、2019年經歷了修訂,新增了半精度(16位)、四倍精度(128位)以及十進位制浮點數等規定,但符號、指數部、尾數部三分結構以及舍入模式的核心思想,自1985年初版以來從未改變。由於幾乎所有程式語言的float/double型別都遵循這一標準,"為什麼0.1+0.2不等於0.3"這一疑問,無論在哪種程式語言中都會以相同的形式出現。