2017-04-05 66 views
1

我有一個Math.Round的bug,沒有任何解釋。 當我做Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72

Math.Round(81.725, 2, MidpointRounding.AwayFromZero) 

結果是81,72但是當我做與Decimal.Round相同

Decimal.Round(81.725M, 2, MidpointRounding.AwayFromZero) 

結果是81,73

我闖到大明白爲什麼,有沒有系統地使用Math.Round的解決方案?下面

+2

http://stackoverflow.com/questions/1165761/decimal-vs-double-which-one-should-i-use-and-when | 你知道十進制和浮點(double,float)有什麼區別嗎? – user2184057

+0

你的問題不是因爲'Math.Round'和'Decimal.Round'。這是因爲您的輸入值在一種情況下是雙倍,而在另一種情況下是小數。試試'Math.Round(81.725M,2,MidpointRounding.AwayFromZero);'你會看到結果是一樣的 – Pikoh

回答

3

你不應該談論錯誤瞭解如何前工作double,並與decimal解釋你所看到的行爲差異。

雙是一個實數與以下結構的最佳近似:

number = sign * mantissa * 2^exponent 

因此,當表示爲double數量81.725,,真的是:

1 * 2875442808959795 * 2^-45 = 81,724999999999994315658113919199 

現在你應該瞭解爲什麼Math.Round(81.725, 2)解析爲81.72而不是81.73

這不會發生在decimal,因爲decimal,與double相反,可以完全代表81.725。這是因爲decimal中的縮放因子是10的一個冪。

這種增加的精度顯然是以成本,速度,空間和範圍爲代價的。何時選擇一種或另一種類型,可以在評論中提供的另一個SO問題的鏈接中得到很好的解釋。

+0

感謝您的詳細解釋 – ArDumez

0

M的後綴上第二分配確定數據類型:

Math.Round(81.725, 2, MidpointRounding.AwayFromZero); // double, returns 81.72 

Math.Round(81.725M, 2, MidpointRounding.AwayFromZero); // decimal, returns 81.73 

Decimal.Round(81.725M, 2, MidpointRounding.AwayFromZero); // decimal, returns 81.73 

通過使用後綴時,如decimal代替double治療上第二分配給定的數據類型,使得所述舍入更精確。

MSDN documentation of Math.Round已經提到這一點不同:

註釋呼叫者:

由於精度損失,可能導致從代表 十進制值作爲浮點數或執行算術 的對浮點值的操作,在某些情況下,Round(Double) 方法可能不會將中點值舍入爲最接近的值,即使是 整數。

並且對於Decimal.Round進一步解釋:

此方法的行爲遵循IEEE標準754,第4節。這 這種舍入有時稱爲圓一半甚至或銀行 四捨五入。它最大限度地減少了由一致的 在單一方向舍入中點值所導致的舍入誤差。它相當於 調用Round(Decimal, MidpointRounding)方法與模式 參數MidpointRounding.ToEven

總之,decimal使用IEEE-754,它使用了中點值一致的舍入,而double(和float)使用浮點不具有有限二進制表示。

其他參考:

Declaration suffix for decimal type