什麼是浮點數?

微信搜尋關注「水滴與銀彈」公眾號,第一時間獲取優質技術乾貨。7年資深後端研發,用簡單的方式把技術講清楚。

在上一篇文章中,我們主要介紹了在計算機中使用定點數表示數字的方式。

簡單回顧一下,簡單來說,用定點數表示數字時,會約定小數點的位置固定不變,整數部分和小數部分分別轉換為二進位制,就是定點數的結果。

但用定點數表示小數時,存在數值範圍、精度範圍有限的缺點,所以在計算機中,我們一般使用「浮點數」來表示小數。

這篇文章,我們就來詳細看一下浮點數到底是如何表示小數的,以及浮點數的的範圍和精度有多大。

什麼是浮點數?

首先,我們需要理解什麼是浮點數?

之前我們學習了定點數,其中「定點」指的是約定小數點位置固定不變。那浮點數的「浮點」就是指,其小數點的位置是可以是

漂浮不定

的。

這怎麼理解呢?

其實,浮點數是採用科學計數法的方式來表示的,例如十進位制小數 8。345,用科學計數法表示,可以有多種方式:

8。345 = 8。345 * 10^08。345 = 83。45 * 10^-18。345 = 834。5 * 10^-2。。。

看到了嗎?用這種科學計數法的方式表示小數時,小數點的位置就變得「漂浮不定」了,這就是相對於定點數,浮點數名字的由來。

使用同樣的規則,對於二進位制數,我們也可以用科學計數法表示,也就是說把基數 10 換成 2 即可。

浮點數如何表示數字?

我們已經知道,浮點數是採用科學計數法來表示一個數字的,它的格式可以寫成這樣:

V = (-1)^S * M * R^E

其中各個變數的含義如下:

S:符號位,取值 0 或 1,決定一個數字的符號,0 表示正,1 表示負

M:尾數,用小數表示,例如前面所看到的 8。345 * 10^0,8。345 就是尾數

R:基數,表示十進位制數 R 就是 10,表示二進位制數 R 就是 2

E:指數,用整數表示,例如前面看到的 10^-1,-1 即是指數

如果我們要在計算機中,用浮點數表示一個數字,只需要確認這幾個變數即可。

假設現在我們用 32 bit 表示一個浮點數,把以上變數按照一定規則,填充到這些 bit 上就可以了:

什麼是浮點數?

假設我們定義如下規則來填充這些 bit:

符號位 S 佔 1 bit

指數 E 佔 10 bit

尾數 M 佔 21 bit

按照這個規則,將十進位制數 25。125 轉換為浮點數,轉換過程就是這樣的(D代表十進位制,B代表二進位制):

整數部分:25(D) = 11001(B)

小數部分:0。125(D) = 0。001(B)

用二進位制科學計數法表示:25。125(D) = 11001。001(B) = 1。1001001 * 2^4(B)

所以符號位 S = 0,尾數 M = 1。001001(B),指數 E = 4(D) = 100(B)。

按照上面定義的規則,填充到 32 bit 上,就是這樣:

什麼是浮點數?

浮點數的結果就出來了,是不是很簡單?

但這裡有個問題,我們剛才定義的規則,符號位 S 佔 1 bit,指數位 E 佔 10 bit,尾數 M 佔 21 bit,這個規則是我們拍腦袋隨便定義出來的。

如果你也想定一個新規則,例如符號位 S 佔 1 bit,指數位 E 這次佔 5 bit,尾數 M 佔 25 bit,是否也可以?當然可以。

按這個規則來,那浮點數表示出來就是這樣:

什麼是浮點數?

我們可以看到,指數和尾數分配的位數不同,會產生以下情況:

指數位越多,尾數位則越少,其表示的範圍越大,但精度就會變差,反之,指數位越少,尾數位則越多,表示的範圍越小,但精度就會變好

一個數字的浮點數格式,會因為定義的規則不同,得到的結果也不同,表示的範圍和精度也有差異

早期人們提出浮點數定義時,就是這樣的情況,當時有很多計算機廠商,例如IBM、微軟等,每個計算機廠商會定義自己的浮點數規則,不同廠商對同一個數表示出的浮點數是不一樣的。

這就會導致,一個程式在不同廠商下的計算機中做浮點數運算時,需要先轉換成這個廠商規定的浮點數格式,才能再計算,這也必然加重了計算的成本。

那怎麼解決這個問題呢?業界迫切需要一個統一的浮點數標準。

浮點數標準

直到1985年,IEEE 組織推出了浮點數標準,就是我們經常聽到的

IEEE754 浮點數標準

,這個標準統一了浮點數的表示形式,並提供了 2 種浮點格式:

單精度浮點數 float:32 位,符號位 S 佔 1 bit,指數 E 佔 8 bit,尾數 M 佔 23 bit

雙精度浮點數 float:64 位,符號位 S 佔 1 bit,指數 E 佔 11 bit,尾數 M 佔 52 bit

為了使其表示的數字範圍、精度最大化,浮點數標準還對指數和尾數進行了規定:

尾數 M 的第一位總是 1(因為 1 <= M < 2),因此這個 1 可以省略不寫,它是個

隱藏位

,這樣單精度 23 位尾數可以表示了 24 位有效數字,雙精度 52 位尾數可以表示 53 位有效數字

指數 E 是個無符號整數,表示 float 時,一共佔 8 bit,所以它的取值範圍為 0 ~ 255。但因為指數可以是負的,所以規定在存入 E

在它原本的值加上一個

中間數

127,這樣 E 的取值範圍為 -127 ~ 128。表示 double 時,一共佔 11 bit,存入 E

加上中間數 1023,這樣取值範圍為 -1023 ~ 1024。

除了規定尾數和指數位,還做了以下規定:

指數 E 非全 0 且非全 1:規格化數字,按上面的規則正常計算

指數 E 全 0,尾數非 0:非規格化數,尾數隱藏位不再是 1,而是 0(M = 0。xxxxx),這樣可以表示 0 和很小的數

指數 E 全 1,尾數全 0:正無窮大/負無窮大(正負取決於 S 符號位)

指數 E 全 1,尾數非 0:NaN(Not a Number)

什麼是浮點數?

標準浮點數的表示

有了這個統一的浮點數標準,我們再把 25。125 轉換為標準的 float 浮點數:

整數部分:25(D) = 11001(B)

小數部分:0。125(D) = 0。001(B)

用二進位制科學計數法表示:25。125(D) = 11001。001(B) = 1。1001001 * 2^4(B)

所以 S = 0,尾數 M = 1。001001 = 001001(去掉1,隱藏位),指數 E = 4 + 127(中間數) = 135(D) = 10000111(B)。填充到 32 bit 中,如下:

什麼是浮點數?

這就是標準 32 位浮點數的結果。

如果用 double 表示,和這個規則類似,指數位 E 用 11 bit 填充,尾數位 M 用 52 bit 填充即可。

浮點數為什麼有精度損失?

我們再來看一下,平時經常聽到的浮點數會有精度損失的情況是怎麼回事?

如果我們現在想用浮點數表示 0。2,它的結果會是多少呢?

0。2 轉換為二進位制數的過程為,不斷乘以 2,直到不存在小數為止,在這個計算過程中,得到的整數部分從上到下排列就是二進位制的結果。

0。2 * 2 = 0。4 -> 00。4 * 2 = 0。8 -> 00。8 * 2 = 1。6 -> 10。6 * 2 = 1。2 -> 10。2 * 2 = 0。4 -> 0(發生迴圈)。。。

所以 0。2(D) = 0。00110。。。(B)。

因為十進位制的 0。2 無法精確轉換成二進位制小數,而計算機在表示一個數字時,寬度是有限的,無限迴圈的小數儲存在計算機時,只能被截斷,所以就會導致小數精度發生損失的情況。

浮點數的範圍和精度有多大?

最後,我們再來看一下,用浮點數表示一個數字,其範圍和精度能有多大?

以單精度浮點數 float 為例,它能表示的最大二進位制數為 +1。1。11111。。。1 * 2^127(小數點後23個1),而二進位制 1。11111。。。1 ≈ 2,所以 float 能表示的最大數為 2^128 = 3。4 * 10^38,即 float 的表示範圍為:-3。4 * 10^38 ~ 3。4 * 10 ^38。

它能表示的精度有多小呢?

float 能表示的最小二進位制數為 0。0000。。。。1(小數點後22個0,1個1),用十進位制數表示就是 1/2^23。

用同樣的方法可以算出,double 能表示的最大二進位制數為 +1。111。。。111(小數點後52個1) * 2^1023 ≈ 2^1024 = 1。79 * 10^308,所以 double 能表示範圍為:-1。79 * 10^308 ~ +1。79 * 10^308。

double 的最小精度為:0。0000。。。1(51個0,1個1),用十進位制表示就是 1/2^52。

從這裡可以看出,雖然浮點數的範圍和精度也有限,但其範圍和精度都已非常之大,所以在計算機中,對於小數的表示我們通常會使用浮點數來儲存。

總結

這篇文章我們主要講了數字的浮點數表示方式,總結如下:

浮點數一般用科學計數法表示

把科學計數法中的變數,填充到固定 bit 中,即是浮點數的結果

在浮點數提出的早期,各個計算機廠商各自制定自己的浮點數規則,導致不同廠商對於同一個數字的浮點數表示各不相同,在計算時還需要先進行轉換才能進行計算

後來 IEEE 組織提出了浮點數的標準,統一了浮點數的格式,並規定了單精度浮點數 float 和雙精度浮點數 double,從此以後各個計算機廠商統一了浮點數的格式,一直延續至今

浮點數在表示小數時,由於十進位制小數在轉換為二進位制時,存在無法精確轉換的情況,而在固定 bit 的計算機中儲存時會被截斷,所以浮點數表示小數可能存在精度損失

浮點數在表示一個數字時,其範圍和精度非常大,所以我們平時使用的小數,在計算機中通常用浮點數來儲存

微信搜尋關注「水滴與銀彈」公眾號,第一時間獲取優質技術乾貨。7年資深後端研發,用簡單的方式把技術講清楚。