2016-06-25 66 views
-1

我想圓一個數字,以小數點後7位,但我注意到,Math.Round不與一些數字正常工作:C#Math.Round錯誤?

Math.Round(39.248779999999996,3) => 39.249 
Math.Round(39.248779999999996,4) => 39.2488 
Math.Round(39.248779999999996,5) => 39.248779999999996 
Math.Round(39.248779999999996,6) => 39.248779999999996 
Math.Round(39.248779999999996,7) => 39.248779999999996 

任何人都可以解釋我這種行爲?

+7

這些浮點值。它們不具有任意數字的有限二進制表示。如果您想要精確的表示形式,請將其轉換爲「decimal」類型。 –

+0

問題是我必須將一個double傳遞給外部組件,以至於我無法更改它的方法簽名,並且如果該數字有超過7個小數位,該組件將拋出一個錯誤。有沒有辦法將這個雙數有效地舍入到小數點後7位? – smeegoan

+0

嗯,沒有辦法讓一個double來存儲一個四捨五入的值,這樣就不會有效。外部組件是越野車。雙打沒有固定的小數位數。它應該使用小數類型。 –

回答

4

如果您需要精度,請使用decimal而不是double/float;

var num = 39.248779999999996; // num is double. 
var num = 39.248779999999996m; // num is decimal. 

十進制關鍵字表示一個128位的數據類型。與 浮點類型相比,小數類型具有更高的精度和更小的範圍,因此適用於財務和貨幣 計算。

編輯:

can't表示所有的數字正好在浮點/雙精度:

二進制浮點運算是好的,只要你知道什麼是 怎麼回事,不期望值與您的程序中的 放在一起的小數完全相同,並且不要期望計算浮點數的二進制數 必然會產生精確的結果。即使 兩個數字都用您所使用的類型完全表示,但涉及這兩個數字的操作的結果將不一定完全代表 。這是最容易看到的部門(例如 1/10儘管1和10正好代表 不完全可以代表),但它可以發生在任何操作 - 甚至看似 無害的,如加法和減法。

例如:

double doubleValue = 1f/10f; // => 0.10000000149011612 
decimal decimalValue = 1m/10m; // => 0.1 

您可以截斷數字,以確保7個位數最高,但你不能準確全面的價值:

double value = 39.248779999999996; 

double roundTo = Math.Pow(10, 7); 
double resultResult = Math.Truncate(value * roundTo)/roundTo; 
// result is : 39.2487799 
+0

問題是我必須將一個double傳遞給外部組件,以至於我無法更改它的方法簽名,並且如果該數字具有超過7個小數位,該組件將拋出錯誤。有沒有辦法將這個雙數有效地舍入到小數點後7位? – smeegoan

+0

@smeegoan檢查上面編輯的答案。 – user3185569

+0

我試過了,結果仍然等於39.248779999999996。如果你使用Console.WriteLine來顯示結果,請確保你使用了'Console.WriteLine(result.ToString(「r」));'因爲默認情況下會使用一般的(「G」)格式說明符(https:// msdn 。微軟。com/en-us/library/dwhawy9k.aspx#RFormatString) – smeegoan