真有小夥伴不知道浮點數如何轉二進制嗎?

真有小夥伴不知道浮點數如何轉二進制嗎?

來吧,坐下聊

先前在前文《老大說:誰要再用double定義商品金額,就自己收拾東西走》中已經痛徹心扉地聊過:


在處理諸如 訂單交易貨幣計算、以及商品金額慎用浮點數(double/float)去定義變量,否則可能會遇到各種奇葩的問題,具體示例在那篇文章中都詳細展示過。

當時寫那篇文章的時候,我以為大家對於小數轉二進制的換算早已瞭然於胸,所以也就沒有給出具體的換算過程。結果文章發出來後,私信裡一票小夥伴反饋說,文中那些小數轉二進制的例子到底是怎麼換算出來的,最好詳解一下。

真有小夥伴不知道浮點數如何轉二進制嗎?

得嘞,這不就來了嘛!

順帶聊一句,看來《計組原理》或者說《計算機系統》這門課有必要小規模回爐重造一下了(滑稽)。

不過實不相瞞,CRUD、複製粘貼、調接口、寫業務代碼久了,計算機基礎確實好多都忘了...我也有深有同感!

浮點數在計算機中是如何表示的?

學過 《計算機組成原理》 或者類似 《計算機系統》 這些課程的小夥伴們應該都知道,浮點數在計算機中的存儲方式遵循IEEE 754 浮點數計數標準,可以表示為:

真有小夥伴不知道浮點數如何轉二進制嗎?

採用尾數 + 階碼的編碼方式,更通俗一點說,就是類似於數學課本上所學的科學計數法表示方式:有效數字 + 指數位

因此,只要給出:符號(S)階碼部分(E)尾數部分(M) 這三個維度的信息,一個浮點數的表示就完全確定下來了,所以float和double這兩種類型的浮點數在計算機中的存儲結構就表示成下圖所示這個樣子:

真有小夥伴不知道浮點數如何轉二進制嗎?

真有小夥伴不知道浮點數如何轉二進制嗎?

1、符號部分(S)

0-正 1-負

2、階碼部分(E)(指數部分)

  • 對於float型浮點數,指數部分8位,考慮可正可負,因此可以表示的指數範圍為-127 ~ 128
  • 對於double型浮點數,指數部分11位,考慮可正可負,因此可以表示的指數範圍為-1023 ~ 1024

3、尾數部分(M)

浮點數的精度是由尾數的位數來決定的:

  • 對於float型浮點數,尾數部分23位,換算成十進制就是 2^23=8388608,所以十進制精度只有6 ~ 7位;
  • 對於double型浮點數,尾數部分52位,換算成十進制就是 2^52 = 4503599627370496,所以十進制精度只有15 ~ 16位

所以,浮點數交給計算機存儲的時候,可能會有精度丟失問題!!!因此使用時需要格外小心,如果真因為這一塊出了bug,定位問題還是非常艱難的,所以預防工作要做好。

進制轉換計算案例

上面說的是IEEE標準規定的內容,屬於理論規約。那一個小數到底要怎麼換算成二進制呢?我們得拿實際例子來解釋。

先來個簡單的例子

比如:把十進制小數0.875轉換成二進制,具體怎麼操作?

可以分幾大步走:

1、以小數點為界,拆分

2、整數部分轉換

整數轉二進制我想大家應該都熟悉,使用:除2取餘法 即可。而這裡的0.875整數部分為0,無需操作。

3、小數部分轉換

小數部分的轉換不同於整數部分,採用的是 “乘2取整法” ,圖示一下就明白了:

真有小夥伴不知道浮點數如何轉二進制嗎?

4、合併結果

整數部分 + 小數部分,最終得到二進制結果為0.111。

所以該結果按照上一節所述的尾數 + 階碼的計算機計數方式,則可以表示為:

真有小夥伴不知道浮點數如何轉二進制嗎?

所以對應可得:

  • 符號位:0
  • 階碼(E)部分:若以float為例,應為 127 +(-1)= 126,因此二進制表示為:01111110
  • 尾數部分(M):若以float為例,應為23位,因此尾部補齊後為11000000000000000000000。

因此最終的總結果為(以32位精度float表示):

00111111011000000000000000000000

再來個複雜點例子

再比如:把十進制小數6.36轉換成二進制,具體怎麼操作?

但凡能用圖示,我就不想寫文字,所以用一張圖就可以解釋得明明白白:

真有小夥伴不知道浮點數如何轉二進制嗎?

整數部分 + 小數部分,因此最終得到的結果二進制結果為110.01011100...。

還是按照上一節所述的尾數 + 階碼的計算機計數方式,則可以表示為:

真有小夥伴不知道浮點數如何轉二進制嗎?

所以對應可得:

  • 符號位:0
  • 階碼(E)部分:若以float為例,應為 127 +(2)= 129,因此二進制表示為:10000001
  • 尾數部分(M):1001011100...,其實它本身無限不循環,但若以float型精度來截取23位,則可以表示為10010111000010100011111

因此最終的總結果為(以32位精度float表示):

01000000110010111000010100011111

所以像這種無限位數的尾數情況,用計算機存儲產生截取是必然的,必定會有一定的精度損失!所以這也從根本上解釋了為什麼float或者double這種類型數據使用時的風險性,因此必須要結合實際業務理性考量。

神器加持

大家如果對上面的計算結果不放心,或者想檢查手動換算的結果是否正確,也有直接的這種二進制轉換工具站,典型的比如binaryconvert

真有小夥伴不知道浮點數如何轉二進制嗎?

不想手動換算的,直接去上面輸入,轉換一下即可得到結果,而且可以進制互換,使用非常方便。

回味

有時候回顧一下基礎真的蠻有意思的,比如寫這篇文章時,雖然是很基礎的東西,但是表達出來的過程還是挺有趣的,尤其是畫圖展現的過程,希望能和小夥伴們共勉。


分享到:


相關文章: