2009-04-15 73 views
8

爲什麼下面的程序打印它打印的內容?爲什麼C#中的浮點運算不精確?

class Program 
{ 
    static void Main(string[] args) 
    { 
     float f1 = 0.09f*100f; 
     float f2 = 0.09f*99.999999f; 

     Console.WriteLine(f1 > f2); 
    } 
} 

輸出是

false 
+0

你爲什麼不自己嘗試一下呢? – 2009-04-15 22:14:41

+10

我試過了,我只想知道爲什麼我看到我所看到的。 – Prankster 2009-04-15 22:17:48

回答

3

在這種特殊情況下,這是因爲.09和.999999不能用精確的二進制表示(類似地,1/3不能用精確的十進制精度表示)。例如,0.111111111111111111101111基數2爲0.999998986721038818359375基數10.將1加到先前的二進制數值中,0.11111111111111111111基數2是0.99999904632568359375基數10.沒有精確到0.999999的二進制值。浮點精度也受分配用於存儲指數和尾數的小數部分的空間的限制。此外,與整數類型一樣,浮點也可以溢出其範圍,儘管其範圍大於整數範圍。

運行該位在Xcode調試C++代碼,

浮子myFloat = 0.1;

顯示myFloat的值爲0.100000001。它已關閉0.000000001。不是很多,但如果計算有幾個算術運算,那麼不精確可能會複雜化。

恕我直言,浮點的一個很好的解釋是介紹計算機組織與x86-64的彙編語言& GNU/Linux的由加利福尼亞州立大學的鮑勃·Plantz第14章在索諾瑪(已退休)http://bob.cs.sonoma.edu/getting_book.html。以下是基於該章節。

浮點類似於科學記數法,其中值存儲爲大於或等於1.0且小於2.0(尾數)的混合數,將某個冪(指數)乘以另一個數。浮點數使用基數2而不是基數10,但在Plantz給出的簡單模型中,爲了清晰起見,他使用基數10。設想一個系統,其中兩個存儲位置用於尾數,一個位置用於指數符號*(0代表+和1代表 - ),一個位置用於指數。現在加0.93和0.91。答案是1.8,而不是1.84。

9311表示0.93或9.3倍於-1的-1。

9111表示0.91或9.1倍於-1的-1。

確切的答案是1.84或1.84倍10到0,如果我們有5個職位,這將是18400,但是,只有四個職位,答案是1800或1.8的10倍到零或1.8 。當然,浮點數據類型可以使用四個以上的存儲位置,但位置數量仍然有限。(Plantz,op。cit。)。不僅精度受空間限制,而且「二進制小數值的精確表示僅限於兩個反函數的和。」(Plantz,前述引文)。

0.11100110(二進制)= 0.89843750(十進制)

0.11100111(二進制)= 0.90234375(十進制)

有一個在二進制小數0.9沒有確切表示。即使將這些分數拿出更多的地方也是行不通的,因爲你會在右邊重複1100次。

開始程序員經常看到浮點運算,因爲精度比整數多 。確實,即使增加兩個非常大的整數也會導致溢出。乘法使得它更可能是結果將是非常大的,因此,溢出。當使用兩個整數 時,C/C++中的/運算符會導致小數部分 丟失。但是,浮點表示有其自己的不準確性。 (Plantz,同上)

*在浮點數中,數字的符號和指數的符號都被表示出來。