浮點數類型在電腦裡面的表示方法

來源:互聯網
上載者:User

上次在校園招聘的時候,問了幾個學生一個關於浮點數計算的問題,就是下面的代碼為什麼第一行返回false,而第二行和第三行都返回true。

 

        Console.WriteLine("1.123f + 1.345f == 2.468f ? {0}",

            1.123f + 1.345f == 2.468f); // False

        Console.WriteLine("1.123f + 1.344f == 2.467f ? {0}",

            1.123f + 1.344f == 2.467f); // True

        Console.WriteLine("1.123 + 1.345 == 2.468 ? {0}",

            1.123 + 1.345 == 2.468); // True

 

我們知道,integer類型佔用的是4個位元組,可以表示的數字範圍在2**-32到2**32之間.而且每一個整數在電腦裡面都有相應的記憶體表示方法,例如數字12345的表示方法就是:

00000000 00000000 00110000 00111001

即根據二進位到十進位的轉換方法: 12345 = 213 + 212 + 25 + 24 + 23 + 20

 

而在電腦float型,這種表示方法最大的問題就是如何在二進位裡面儲存小數點的位置--因為小數點的位置不固定.於是電腦專家們就想到了用科學計數法的方式來表示浮點數,因為在科學計數法裡面,小數點的位置總是固定,就是在第一個數位後面,例如12345的科學計數法的表示為: 1.2345 * 105。而0.012345的科學計數法表示方式為: 1.2345 * 10-2.

 

使用公式來表示的話,科學計數法的公式是 。

 

因為我們的電腦比較笨,只能處理0和1,所以在電腦裡面表示浮點數的時候,上面的公式中的基數b是2,而不是10.在電腦記憶體當中,儲存的實際是浮點數的計算公式,而不是確切的值,所以說電腦裡面浮點數都是近似值,而不是確切的值.在電腦中,以float類型為例,記憶體中32個位所代表的內容分別是:

SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM

其中S代表符號位,1代表這個浮點數是一個負數,而0則表示是正數。而E就是科學計數法裡面的指數e,由於 e既有可能是正數,也有可能是負數,因為1234.5的科學計數法是1.2345 * 104,而0.12345的科學計數法是1.2345 * 10-1。所以e的計算規則是EEEEEEE E表示的數減去27- 1(7是因為我們有8個位來表示指數),這樣8個表示指數的位就可以用來表示負數和正數了。

 

而M就是用來計算科學計數法裡面的m,計算規則是,從左往右開始,第一個M代表2-1,第二個M表示2-2,依次類推。由於m要麼就是大於1的小數,要麼就是小於1的小數(記住,我們計數法裡面的基數是2 ,而不是10),如果e的值大於0,那麼我們就可以加上這個1,如果e的值小於0,那麼我們可以省略這個1,這是因為我們總是可以通過調整e的值來做到這一點。因此m裡面小數點前面的1被省略掉了,這個省略掉的1可以根據e的值來推算出m的小數點前面到底有沒有這個1。

 

而對於double類型來說,在電腦中各個位表示的資訊如下所示:

SEEEEEEE EEEEMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM

現在我們再回過頭來看看上面的代碼:

        double a = 1.345f;

        double b = 1.123f;

        double result = a + b;

        double expected = 2.468f;

 

        Console.WriteLine("result == expected ? {0}", result == expected);

調試這個程式,在記憶體中看一看a的值是3ff5851ec0000000(為了說明方便,我將文章開頭的程式改頭換面了一下),在計算機裡面將這個十六進位的值換算成二進位的是:

11111111110101100001010001111011000000000000000000000000000000

 

因為計算機會將首碼零省略掉,因此上面的值實際上是:

00111111 11110101 10000101 00011110 11000000 00000000 00000000 00000000

 

由於e部分的值大於等於0,因為127 – (27 – 1) = 1,所以我們在計算m的時候需要加上隱含的1,也就是說上面黃色背景的值實際上表示的是:

 

(十進位的)1.0 + 0101 10000101 00011110 11000000 00000000 00000000 00000000所表示的小數

= 1.0 + 2**-2 + 2**-4 + 2**-5 + 2**-10 + 2**-12 + 2**-16 + 2**-17 + 2**-18 + 2**-19 + 2**-21 + 2**-22

= 1.0 + 0.25

      + 0.0625

      + 0.03125

      + 0.0009765625

      + 0.000244140625

      + 0.0000152587890625

      + 0.00000762939453125

      + 0.000003814697265625

      + 0.0000019073486328125

      + 0.000000476837158203125

      + 0.0000002384185791015625

= 1.0 + 0.3450000286102294921875

= 1.3450000286102294921875

 

因此按照上面的演算法,b的值實際上應該是1.1230000257492065,因此a + b實際上是2.468000054359436,而上面的程式expected的實際值應該是2.4679999351501465,這就是為什麼上面1.345f + 1.123f != 2.468f的原因。

 

而1.344f + 1.123f == 2.467f,純粹是巧合,因為前兩者相加的值恰好等於後者在電腦裡面的表現形式。

 

最後洋洋洒洒一大篇的結論就是,浮點類型不能用==號來判斷,因為浮點數是一個近似值,只能通過兩者相減小於一個可以接受的誤差來判斷。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.