2012-02-10 123 views
23

在.NET中,爲什麼System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero)產生1.03而不是1.04?我覺得我的問題的答案在於http://msdn.microsoft.com/en-us/library/ef48waz8.aspx的標題爲「給致電者的提示」部分,但我無法圍繞解釋說明。爲什麼在這種情況下System.MidpointRounding.AwayFromZero沒有取整?

+0

有趣的是,調用此方法與收益1.135 1.14的數值。 – 2012-02-10 00:51:44

+10

「說明」基本上是基數爲2的數字。它不能精確地表示某些值*。您輸入1.035,內部表示可能是1.034999999982或其他。如果您對位數的確切表示方式感興趣,可能是System.Decimal是您的類型。特別是如果你正在處理財務價值。 – 2012-02-10 00:53:33

+1

@KyleTrauberman這是因爲在1.135時你很幸運 - 近似值比1.135略高,而不像OP那樣。 – 2012-02-10 01:13:01

回答

26

你的懷疑是完全正確的。帶小數部分的數字在.NET中以文字表示時默認爲doubles。雙精度(如浮點數)是十進制值的近似值,而不是精確的十進制值。它是可以用基-2(二進制)表示的最接近的值。在這種情況下,近似值在1.035的小方面是非常消失的。如果您在使用它工作的明確的小數寫它,你希望:

Console.WriteLine(Math.Round(1.035m, 2, MidpointRounding.AwayFromZero)); 
Console.ReadKey(); 

要理解爲什麼雙打和彩車工作他們的方式,想象代表十進制(數1/3或二進制,從遭受同樣的問題)。你不能將它翻譯爲.3333333 ....,這意味着要準確表示它需要無限量的內存。

計算機使用近似值解決此問題。我會詳細解釋,但我可能會弄錯。你可以在這裏閱讀所有關於它雖然:http://en.wikipedia.org/wiki/IEEE_754-1985

+0

注意,默認值是* double。* 1.0隱式地是雙精度型,儘管它可以在1d或1.0d中顯式設置。浮點文字需要'f'後綴。 – 2012-02-10 00:57:47

+0

固定,謝謝安迪爾 – 2012-02-10 01:01:14

+0

@ChrisShain double確實是一個精確的值;它只是一個精確的二進制值,它可能或可能不是近似於文字所指示的精確十進制值。例如,二進制值「0.25d」正好等於十進制值0.25。另外,我認爲你的意思是「想象代表小數1/3」,因爲0.33333 ...是十進制表示,而不是二進制。二進制表示更像0.0101010101 ... – phoog 2012-02-10 01:04:33

1

在猜測我會說,內部1.035不能用二進制表示爲1.035,它可能(在引擎蓋下)1.0349999999999999,這就是爲什麼它下降。

只是一個猜測。

3

我相信你提到的例子是一個不同的問題;據我所知,他們說0.1不是以浮點形式存儲,正如0.1,但實際上由於浮點數如何存儲在二進制文件中,它實際上是稍微關閉的。因此,讓我們假設它實際上看起來更像0.0999999999999(或類似的),非常略微小於0.1 - 這樣稍微有點不會有太大的改變。呃,他們在說:不同的是,一個明顯的區別是將這個加到你的數字和四捨五入實際上會出錯,因爲即使數字非常接近,它仍然被認爲是「小於」.5的四捨五入。

如果我誤解了該網頁,我希望有人糾正我:)

我看不出它與您的電話,不過,因爲你是更加明確。也許它只是以類似的方式儲存你的號碼。

+0

完全正確。 – 2012-02-10 00:57:02

+0

+1「因爲如何以二進制形式存儲浮點數」。 – phoog 2012-02-10 01:07:28

6

I'ts因爲1.035的二進制表示更接近1.03比1.04

爲了獲得更好的成績做這種方式 -

decimal result = decimal.Round(1.035m, 2, MidpointRounding.AwayFromZero); 
7

的1.035d二進制表示0x3FF08F5C28F5C28F,這實際上是1.03499999999999992006394222699E0,所以System.Math.Round(1.035,2,MidpointRounding.AwayFromZero)得到1.03,而不是1.04 ,所以這是正確的。

然而,4.005d的二進制表示是0x4010051EB851EB85,這是4.00499999999999989341858963598,所以System.Math.Round(4.005,2,MidpointRounding.AwayFromZero)應產生4.00,但它產生4.01這是錯誤的(或智能'固定')。如果你在MS SQL中選擇ROUND(CAST(4.005 AS float),2),它是4.00 我不明白爲什麼.NET應用這個「智能修復」,這讓事情變得更糟。

您可以檢查雙二進制表示: http://www.binaryconvert.com/convert_double.html

相關問題