float類型在記憶體中的表示

來源:互聯網
上載者:User

先說一下電腦中二進位的演算法:

  • 整數 
    整數的二進位演算法大家應該很熟悉,就是不斷的除以2取餘數,然後將餘數倒序排列。比如求9的二進位: 
    9/2=4 餘 1 
    4/2=2 餘 0 
    2/2=1 餘 0 
    1/2=0 餘 1 
    一直計算到商為0為止,然後將得到的餘數由下到上排列,就得到了9的二進位:1001。 
    從上面的演算法我們可以看到,用整數除以2,最終都能夠到0。因此,整數是可以用二進位來精確表示的。
  • 小數 
    小數的二進位演算法和整數的大致相反,就是不斷的拿小數部分乘以2取積的整數部分,然後正序排列。比如求0.9的二進位: 
    0.9*2=1.8 取 1 
    0.8*2=1.6 取 1 
    0.6*2=1.2 取 1 
    0.2*2=0.4 取 0 
    0.4*2=0.8 取 0 
    0.8*2=1.6 取 1 
    … … 
    如此迴圈下去。因此我麼得到的二進位小數也是無限迴圈的:0.11100110011... 
    從小數的二進位演算法中我們可以知道,如果想讓這種演算法停止,只有在小數部分是0.5的時候才可以,但是很不幸,這類的小數很少。所以大部分小數是很難用二進位來精確表示的。

------------------------我是分割線------------------------------ 

OK,有了上面的知識,我們進入正題:看看float類型在記憶體中是如何表示的。  
float類型又稱為單精確度浮點類型,在 IEEE 754-2008 中是這樣定義它的結構的:

  S     EEEEEEEE      FFFFFFFFFFFFFFFFFFFFFFF
31   30        23    22                               0

 

float類型總共4個位元組——32位:

  1. 符號位
    其中最左邊的為符號位,0為正,1為負。
  2. 指數
    接下來的E是指數,一共8位,也用二進位來表示。
  3. 尾數
    最後的F是小數部分,尾數正是由這23位的小數部分+1位組成的。(這個稍後解釋)。

這裡我們需要多說一下指數。雖然指數也是用8位二進位來表示的,但是IEEE在定義它的時候做了些手腳,使用了位移來計算指數。

IEEE規定,在float類型中,用來計算指數的位移量為127。也就是說,如果你的指數實際是0,那麼在記憶體中存的就是0+127=127的二進位。稍後我們來看這個到底如何使用。

 

好了,看了這麼多,我們該示範一下電腦如何將一個十進位的實數轉換為二進位的。就拿6.9這個數字來舉例吧。-_-||!

 

首先,我們按照上面說的方法,分別將整數和小數轉換成對應的二進位。這樣6.9的二進位表示就是110.1110011001100...。這裡就看出來
了,6.9轉換成二進位,小數部分是無限迴圈的,這在現在的電腦系統上是無法精確表示的。這是電腦在計算浮點數的時候常常不精確的原因之一。

 

其次,將小數點左移(或右移)到第一個有效數字之後。說的通俗些,就是把小數點移到第一個1之後。這樣的話,對於上面的110.1110011001100...我們就需要把小數點左移2位,得到1.101110011001100...。

 

接下來的事情就有意思了。首先我們把得到的1.101110011001100..這個數,從小數點後第一位開始,數出23個來,填充到上面float記憶體
結構的尾數部分(就是那一堆F的地方),我們這裡數出來的就是10111001100110011001100。這裡又要發生一次不精確了,小數點後超出 23位的部分都將被捨棄,太慘了。

 

不過,這裡有一個可能讓大家覺得特別坑爹的事情,就是小數點前面的1也不要了。仔細看看上面的記憶體結構,確實沒有地方存放這個1。原因是這樣的:IEEE覺
得,既然我們大家都約定把小數點移動到第一個有效數字之後,那也就預設小數點前面一定有且只有一個1,所以把這個1存起來也浪費,乾脆就不要了,以後大家 都這麼默契的來就好。這也是為什麼我上面說尾數是23位+1位的原因。

 

填充完尾數,該填充指數了。這個指數就是剛才我們把小數點移動的位元,左移為正,右移為負,再按照上面所說的位移量演算法,我們填充的指數應該是2+127=129。轉換成8位二進位就是10000001。

 

最後,根據這個數的正負來填充符號位。我們這裡是正數,所以填0。這樣6.9的在記憶體中的儲存結果就出來了:

0  10000001  10111001100110011001100

 

總結一下,實數轉二進位float類型的方法:

A. 分別將實數的整數和小數轉換為二進位
B. 左移或者右移小數點到第一個有效數字之後
C. 從小數點後第一位開始數出23位填充到尾數部分 
D. 把小數點移動的位元,左移為正,右移為負,加上位移量127,將所得的和轉換為二進位填充到指數部分
E. 根據實數的正負來填充符號位,0為正,1為負

如果需要把float的二進位轉換回十進位的實數,只要將上面的步驟倒著來一邊就行了。

 

------------------------我是分割線------------------------------

需要注意的東西:

  1. 23位尾數填充的問題
    雖然在IEEE754標準中我沒有找到相應的描述,但是在實際處理的時候,截取23位尾數需要對第24位進行零舍一入的操作,至少在Java虛擬機器中是這麼做的。有興趣的可以試試0.7f-0.6f。
  2. 運算時向右對階操作的舍入問題
    這個也是在實際操作時遇到的問題。到目前為止我還無法確定向右對階操作是否也進行了零舍一入的操作。有興趣的可以試試9.6f-6.9f。
  3. 指數全零問題
    全部為零的指數說明當前所表示的是一個特殊的float數字。全零的float類型分為兩種情況:  
    • 尾數全零。此時代表當前float數為0。根據符號位,分為+0和-0。這兩個在JVM上相等的。 
      這裡需要解釋一下。因為IEEE的預設1的問題,所以float類型沒有辦法表示0,因此只能在已有的規定上做一些強制性的規則來表示0,也就有了上面的這個全零的說法。  
    • 尾數不全為零。此時說明當前的float數是一個非規格化的數。
  4. 指數全一問題
  5. 指數全部為一也說明這個float數是一個不尋常的數字。它也分為兩種情況:  
    • 尾數全零。此時根據符號位的不同,分為正無窮(+infinity)和負無窮(-infinity)。注意,這兩個東西在JVM中是不相等的。
    • 尾數不全為零。此時表示此float數純粹不是一個數(NaN,Not a Number)。這個NaN也分為QNaN(Quiet NaN)和SNaN(Signalling
      NaN)。至於這兩個NaN有什麼區別,下面這段話倒是說明了,但是我沒有這方面的知識,所以不敢妄加翻譯,只好把原文放在這裡:
      A QNaN is a NaN with the most significant fraction bit set. QNaN's propagate
      freely through most arithmetic operations. These values pop out of an operation when the result is not mathematically defined.
      An SNaN is a NaN with the most significant fraction bit clear. It is used to signal an exception when used in operations. SNaN's can be handy to assign to uninitialized variables to trap premature usage. 
      Semantically, QNaN's denote indeterminate operations, while SNaN's denote invalid operations. 
      最後一句話說的明白,QNaN就是一個不確定操作的結果,而SNaN純粹就是一個非法的操作結果。

------------------------我是分割線-----------------------------

OK,廢話了這麼多,我覺得對float類型也大致有個瞭解了。float明白了以後,double類型也就好說了,基本和上面一樣,只是指數和尾數的位元不一樣而已。

 

參考:

IEEE Standard 754 Floating Point Numbers: http://steve.hollasch.net/cgindex/coding/ieeefloat.htm

IEEE 754-1985: http://en.wikipedia.org/wiki/IEEE_754-1985

IEEE 754-2008: http://en.wikipedia.org/wiki/IEEE_754-2008

Java 理論與實踐: 您的小數點到哪裡去了?: http://www.ibm.com/developerworks/cn/java/j-jtp0114/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.