微信搜索關注「水滴與銀彈」公衆号,第一時間獲取優質技術幹貨。7年資深後端研發,用簡單的方式把技術講清楚。
在上一篇文章中,我們主要介紹了在計算機中使用定點數表示數字的方式。
簡單回顧一下,簡單來說,用定點數表示數字時,會約定小數點的位置固定不變,整數部分和小數部分分别轉換為二進制,就是定點數的結果。
但用定點數表示小數時,存在數值範圍、精度範圍有限的缺點,所以在計算機中,我們一般使用「浮點數」來表示小數。
這篇文章,我們就來詳細看一下浮點數到底是如何表示小數的,以及浮點數的的範圍和精度有多大。
什麼是浮點數?首先,我們需要理解什麼是浮點數?
之前我們學習了定點數,其中「定點」指的是約定小數點位置固定不變。那浮點數的「浮點」就是指,其小數點的位置是可以是漂浮不定的。
這怎麼理解呢?
其實,浮點數是采用科學計數法的方式來表示的,例如十進制小數 8.345,用科學計數法表示,可以有多種方式:
8.345=8.345*10^0
8.345=83.45*10^-1
8.345=834.5*10^-2
...
看到了嗎?用這種科學計數法的方式表示小數時,小數點的位置就變得「漂浮不定」了,這就是相對于定點數,浮點數名字的由來。
使用同樣的規則,對于二進制數,我們也可以用科學計數法表示,也就是說把基數 10 換成 2 即可。
浮點數如何表示數字?我們已經知道,浮點數是采用科學計數法來表示一個數字的,它的格式可以寫成這樣:
V=(-1)^S*M*R^E
其中各個變量的含義如下:
如果我們要在計算機中,用浮點數表示一個數字,隻需要确認這幾個變量即可。
假設現在我們用 32 bit 表示一個浮點數,把以上變量按照一定規則,填充到這些 bit 上就可以了:
假設我們定義如下規則來填充這些 bit:
按照這個規則,将十進制數 25.125 轉換為浮點數,轉換過程就是這樣的(D代表十進制,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 種浮點格式:
為了使其表示的數字範圍、精度最大化,浮點數标準還對指數和尾數進行了規定:
除了規定尾數和指數位,還做了以下規定:
有了這個統一的浮點數标準,我們再把 25.125 轉換為标準的 float 浮點數:
所以 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->0
0.4*2=0.8->0
0.8*2=1.6->1
0.6*2=1.2->1
0.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。
從這裡可以看出,雖然浮點數的範圍和精度也有限,但其範圍和精度都已非常之大,所以在計算機中,對于小數的表示我們通常會使用浮點數來存儲。
總結這篇文章我們主要講了數字的浮點數表示方式,總結如下:
微信搜索關注「水滴與銀彈」公衆号,第一時間獲取優質技術幹貨。7年資深後端研發,用簡單的方式把技術講清楚。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!