2013-07-18 81 views
1

在C中,當浮動設置,使C漂浮精確?

int main(int argc, char *argv[]) { 
    float temp = 98.6f; 
    printf("%f\n", temp); 
    return 0; 
} 

它似乎總是得到一些舍入誤差,

98.599998 

但是當我使其更加精確,

float temp = 96.600000f; 

它仍然打印一個不同的數字。這應該如何解決?

+12

請閱讀[每位計算機科學家應該瞭解的浮點算術知識](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)瞭解深入信息說明。 –

+0

另請參見[定點算術](http://en.wikipedia.org/wiki/Fixed-point_arithmetic) - 一般不會取代浮點數,但它是解決一些問題的另一種方法。 – user2246674

+1

另一個很好的參考:http://floating-point-gui.de/ – abelenky

回答

4

添加尾隨零永遠不會有所作爲。

問題是,32位浮點數不能精確表示96.6,句號。

它不是隨機挑選數字來填補你遺漏的;它將它四捨五入到它能表達的最接近的數字。

10

它仍然打印一個不同的數字。這應該如何解決?

通過使用不同的數據類型,如果你想精確十進制值。

二進制浮點數精確 - 它只是它們的精確值二進制值。例如,如果要基數3表示小數,則小數不精確。例如,如果要表示基數3中的數字,則十進制不精確。沒有精確的二進制表示形式,只有0.1個十進制,就像沒有「三分之一」的精確十進制表示形式。

這完全取決於您的要求是什麼,並使用與之匹配的數據類型。對於精確的十進制值,您可能最好使用第三方庫......或者保留一個您知道的整數邏輯上由100或10,000等等縮放的整數。

+0

什麼是二進制浮點數? –

+0

@EdHeal:一個浮點類型的值,浮點「浮點」是一個二進制點。例如,八分之一是二進制的0.001,可以表示爲「尾數爲1,指數爲-3」(取決於確切的表示)。 –

+0

@JonSkeet所以它就像基數2中的小數?所以雖然'1100'是小數點後12位,'1100.01'小數點後是12.25? – tkbx

3

它與平臺有關,但通常像98.6這樣的數字不能完全表示。

你可以做的是使用printf精度說明等,以顯示"%.2f"「圓圓」的數量。

+0

對於「_usually_像98.6這樣的數字不能完全表示」。浮點_could_應該是十進制的,然後是98.6。即G。 IEEE 754 decimal32。 – chux

1

沒有簡單的答案。它與浮動在記憶中的表現有關,但我們傾向於認爲它們可以代表所有實數。他們不能。如果你想精確地使用浮點數,可以考慮小於或大於範圍,而不是試圖將它們等同起來。在你的例子中,嘗試使用%f2.1(或類似的)在小數點右側打印出少量的數字。

0

給出的是字float。它由尾數和指數組成。該值是它可以在有限的位數中實現的最佳表示形式(以pi爲例)。

所以不要使用相等,因爲你得到舍入錯誤。你可以採取措施儘量減少他們,但這需要幾個講座和一本教科書。

順便說一句 - 不要使用花車錢。更好地使用整數並以毫米/分鐘計算東西/ ...

+1

你的回答並不能解釋爲什麼「98.6」不能完全表示。這裏的關鍵問題不在於它是浮點數 - 它是浮點數是* binary *點,而源數據是* decimal *。 –

6

這是以二進制形式表示十進制數的基本限制。二進制浮點數用2的冪表示,而十進制數用10的冪表示,而C的float根本無法精確地表示所有的十進制數。

你舉的例子數,96.1可以寫成:

96.1 = 9*10^1 + 9*10^0 + 1*10^-1 

以二進制表示這一點,你可以得到整數96就好了:

96 = 1*2^6 + 1*2^5 

但代表0.1是有問題基數2.前幾個二進制小數位的數值爲:

2^-1 = 0.5 
2^-2 = 0.25 
2^-3 = 0.125 
2^-4 = 0.0625 
2^-5 = 0.03125 
2^-6 = 0.015625 
2^-7 = 0.0078125 
2^-8 = 0.00390625 
2^-9 = 0.001953125 
... and so on 

因此,不知何故y您需要使用這些位置值的組合來加起來約爲0.1的十進制數。所以你必須以b0.0001(d0.0625)作爲第一個小於d0.1的開始,並且增加一些更小的位置值以接近和接近0.1。例如:

b0.001  = d0.125  // too high, try lower 
b0.0001  = d0.0625  // too low, so add smaller places 
b0.00011 = d0.09375 // good, closer... rounding error is 0.0625 
b0.000111 = d0.109375 // oops, a little high 
b0.00011001 = d0.09765625 // getting better - how close do you need? 
... 

等等 - 你明白了。因此,由於基本表示,二進制值只能近似小數。

有許多關於浮點舍入誤差和表示限制的文章。絕對值得做一些關於這個話題的背景閱讀。

有解決這個問題的一些方法:

  • 使用float但仍然意識到了限制,並精心設計了算法,以儘量減少舍入誤差
  • 使用準確的十進制表示,如BCD(二進制用於金融系統以避免舍入誤差
  • 使用固定數據類型,其中數字用整數小數表示,並且只在計算結束時轉換爲浮點數以顯示結果。
+1

*二進制*浮點數用2的冪來表示。擁有非二進制浮點數是完全可行的 - 浮點數的概念就是有一個尾數和一個指數,它在某些基礎上被解釋。例如,.NET中的System.Decimal是一個十進制浮點數。 –