1. 程式人生 > >三:計算機進行小數運算時出錯的原因

三:計算機進行小數運算時出錯的原因

方法 了解 誤差 浮點 alt wid 方式 進行 必須

0、開篇:

(1)二進制數0.1,用十進制數表示的話是多少? 0.5 (2)用小數點後有3位的二進制數,能表示十進制數0.625嗎? 可以,0.101 (3)將小數分為符號、尾數、基數、指數4部分進行表現的形式稱為什麽? 浮點數(浮點數形式) (4)二進制數的基數是什麽? 2 (5)通過把0作為數值範圍的中間值,從而在不使用符號位的情況下來表示負數的表示方法稱為什麽? EXCESS系統表示(EXCESS是“剩余的”的意思。例如,把01111111看作是0的話,比這個數小1的01111110就是-1) (6)10101100.01010011這個二進制數,用十六進制數表示的話是多少? AC.53

1、將0.1累加100次也得不到10

技術分享

技術分享

2、用二進制數表示小數

  先來一個熱身,把1011.0011這個有小數點的二進制數轉換成十進制數(前面章節已經講過了用二進制來表示整數的方法,其實小數也一樣),如下圖所示:

  技術分享

3、計算機運算出錯的原因

   通過第2節的學習,大家應該也能大概知道計算機運算出錯的原因了:是因為“有一些十進制數的小數無法轉換成二進制數”。例如十進制數0.1,就無法用二進制數正確表示,小數點後面即使有幾百位也無法表示。

 我們就看小數點後4位用二進制數表示時的數值範圍0.0000~0.1111,如下圖所示:

  技術分享

  這裏只能表示0.5 、 0.25 、 0.125 、0.0625這四個二進制數小數點後面的位權組合而成(相加總和)的小數。再回到我們要表示的0.1,怎麽加都無法加到0.1的,只會變成0.00011001100...(1100的循環),不信你可以去試試。

說到這裏,大家應該都能明白為什麽將0.1累加100次也得不到10的原因了把,因為無法正確表示的數值,最後都變成了近似值。計算機是一個功能有限的機器設備,是無法處理無限循環的小數的,一般計算機都會從中間截斷。

4、什麽是浮點數

  像1011.0011這樣帶小數點的表現形式,完全是紙面上的二進制數表現形式,在計算機內部是無法使用的。這一章節主要是說明計算機是以什麽樣的表現形式來處理小數。很多編程語言中都提供了兩種表示小數的數據類型,分別是雙精度浮點數與單精度浮點數。雙精度浮點數類型用64位、單精度浮點數用32位來表示全體小數。從C語言中,雙精度浮點數類型和單精度浮點數類型分別用double和float來表示。

  浮點數是指符號、尾數、基數和指數這四個部分來表示的小數,如下圖:

  技術分享

  因為計算機內部使用的是二進制,所以基數自然就是2.因此,實際的數據中往往不考慮基數,只用符號、尾數、指數這三部分即可表示浮點數。也就是說,64位(雙精度浮點數)和32位(單精度浮點數)的數據,會被分為三部分來使用,如下圖展示:

  技術分享

 ① 符號部分:是指使用一個數據位來表示數值的符號。該數據位是1時表示負,為0時則表示“正或者0”。 ② 尾數部分:數值大小的決定部分之一(另外一個是指數部分)。尾數部分用的是“將小數點前面的值固定為1的正則表達式”。 ③ 指數部分:用的則是EXCESS系統表現。

5、正則表達式和EXCESS系統

   ① 尾數部分使用正則表達式,可以將表現形式多樣的浮點數統一為一種表現形式。例如十進制的0.75就有很多種表現形式:

  技術分享 

正因為表現形式太多,計算機處理時就會比較麻煩。因此,為了方便計算機處理,需要制定一個統一的規則。例如,十進制數的浮點數應該遵循“小數點前面是0,小數點後面第1位不能是0”這樣的規則。根據這個規則,0.75就是“0.75 * 10的0次冪”,也就是說,只能用尾數部分是0.75、指數部分是0這個方法來表示。根據這個規則來表示小數的方式,就是正則表達式。 二進制數也是同樣的道理,在二進制數中,我們使用的是“將小數點前面的值固定為1的正則表達式”。具體來講,就是將二進制數表示的小數左移或右移(這裏是邏輯移位。因為符號位是獨立的)數次後,正數部分的第1位變為1,第2位之後都變為0(這樣是為了消除第2位以上的數位)。而且,第1位的1在實際的數據中不保存。由於第1位必須是1,因此,省略該部分後就節省了一個數據位,從而也就可以表示更多的數據範圍。 下圖是單精度浮點數的正則表達式的具體例子(單精度浮點數中,尾數部分是23位):

  技術分享

6、在實際的程序中進行確認

  對EXCESS系統與正則表達式了解了嗎,如果還沒有了解,就返回上一小節再看一看,我也是看了幾遍才看懂的,如果看懂了,就往下看,用C語言程序來確認單精度浮點數表示方法。

7、如何避免計算機計算出錯 

  計算機計算出錯的原因之一是采用浮點數來處理小數(另外,也有因“位溢出”而造成計算錯誤的情況)。作為程序的數據類型,不管是使用單精度浮點數還是雙精度浮點數,都存在計算出錯的可能性。接下來會介紹兩種避免該問題的方法。 ① 回避策略,即無視這個錯誤,只要得到近似值就可以了,那些微小的誤差完全可以忽略掉。 ② 把小數轉換成正數來計算。

8、二進制數和十六進制數 

  最後補充說明一下二進制數和十六進制數的關系。在實際程序中,如果二進制位數太多,看起來會比較麻煩,因此,在實際程序中,也經常會用十六進制數來代替二進制數。二進制數的4位,正好相當於十六進制數的1位。例如,32位二進制數00111101110011001100110011001101用十六進制數來表示的話,就是3DCCCCCD這個8位數。由此可見,通過使用十六進制數,二進制數的位數能夠縮短至原來的1/4 。 用十六進制數來表示二進制小數時,小數點後的二進制數的4位同樣相當於十六進制的1位。不夠4位時用0填補二進制數的低位即可。例如,1011.011的低位補0後為1011.0110,這時就可以表示為十六進制數B.6 。  技術分享

三:計算機進行小數運算時出錯的原因