2011-07-27 61 views
10

我試圖對象與價值0.39999999999999997轉換爲十進制變量不失精度。C#轉換對象爲十進制

object d = 0.39999999999999997; 

我試過以下方法。

decimal val1 = Convert.ToDecimal(d); // val1 = 0.4 
object val2 = Convert.ChangeType(d, Type.GetType("System.Decimal")); // val2 = 0.4 
decimal val3 = decimal.Parse(d.ToString()); // val3 = 0.4 
decimal val4 = (Decimal) d; // val4 = 0.4 

我知道這不是一個問題,小數數據類型無法存儲此值,如下圖所示。

decimal val5 = 0.39999999999999997m; // val5 = 0.39999999999999997; 

如何將此對象轉換爲十進制而不會丟失精度?

我正在使用.NET Framework 3.5。

+0

不是很確定你能保證裝箱/拆箱和不同的浮點類型之間的轉換持續性的精度。 – Tigran

回答

8

我覺得這是你要找的代碼:

object d = 0.39999999999999997; 
//Unbox value 
double doubleVal = (double)d; 

//Convert to string. R format specifier gives a string that can round-trip to an identical number. 
//Without R ToString() result would be doubleAsString = "0.4" 
string doubleAsString = doubleVal.ToString("R"); 

//Now that you have doubleAsString = "0.39999999999999997" parse it! 
decimal decimalVal = decimal.Parse(doubleAsString); 
+0

完美。雖然我擔心使用雙打會影響數據的準確性,但這似乎是迄今爲止最好的選擇。謝謝。 –

+0

那麼在這種情況下,我同意V4Vendettas的評論:'我恐怕不可能,因爲對象持有對值的引用,並且在你的情況下,除非引用是十進制的,否則實際上不能獲得該精度' – Reniuz

+0

謝謝。很好的解釋。 :) –

0
string val = "0.39999999999999997"); 
decimal d = decimal.Parse(val, 
    System.Globalization.NumberStyles.AllowDecimalPoint);//0.39999999999999997 
+0

'object d = 0.39999999999999997; double decim = double.Parse(d.ToString(),System.Globalization.NumberStyles.AllowDecimalPoint); // decim = 0.4' –

+0

@Chathura:這是一個錯字。我的意思是'decima.Parse'我測試了它,結果如預期。 –

+0

嘿,弦在哪裏出現? – V4Vendetta

0

Decimal d = new Decimal(d);

如果d是一個雙,然後根據文檔MSDN本應該保持精度。

此構造函數使用舍入到最近值將值舍入爲15位有效數字。即使數字超過15位數字並且低位有效數字爲零,也會執行此操作。

+0

不起作用。無法將對象傳入Decimal()構造函數。 –

+0

.Net 4.0和3.5都具有帶雙精度值的構造函數... – Spence

0
此頁面 http://msdn.microsoft.com/en-us/library/364x0z75(v=vs.80).aspx它寫在

「沒有使用後綴m,數字被視爲一個雙」
而這種代碼

object o = 0.39999999999999997; 
Console.WriteLine(o.GetType()); 

顯示出來System.Double

,而這一個

object o = 0.39999999999999997m; 
Console.WriteLine(o.GetType()); 

顯示出來System.Decimal
所以你只是失去了你的精度沒有後綴米。

+0

Decimal類型是必需的,因爲Double存儲它的值的​​方式,它不存儲我輸入的確切值。例如12.03將被存儲爲12.029999999999999等。 –

4

對於這個工作,你需要將它分配同樣

object d = 0.39999999999999997M; 

沒有辦法的對象,除非你把它強制保持精度。 (如果這不是實際的代碼,你將需要出示其分配如何)

只有這樣,像這樣的工作decimal dec = Convert.ToDecimal(d);

+0

由於這個變量被初始化的方式(實際值被存儲在數據庫中),我無法知道它什麼時候會是十進制值。 –

+0

如果您無論如何將要使用小數爲什麼不獲取數據庫值並將其轉換爲十進制,那麼問題是什麼? – V4Vendetta

+0

讓我澄清。這是一個接受對象的通用方法。而且我無法更改方法簽名。 –

0

對象d = 0.399999999999999999999999997M; 會工作。

+0

不是一個選項。實際值從數據庫中檢索。 –

1

當你正在閱讀從數據庫中的數據(如你在一個評論指出,海事組織你應該補充說,你的問題)我想這是一個可怕的想法,允許轉換爲一倍,背部,同時從數據庫中讀取,因爲你會失去精度[可能它保存爲固定點或在多個系統,可以代表小數。 我認爲你必須付出一些努力直接讀取存儲的值作爲小數(編輯你的模式或類似的東西),或者如果它不可能,然後讀取它們作爲字符串,並使用Decimal.Parse()獲取實際值。

其實您的號碼爲0.39999999999999997有17位小數,因此它不能安全地存儲爲double。

P.S.關於.net雙打和Jon Skeet寫的四捨五入有a great article

+0

我知道這是一個壞主意,轉換爲一個雙和返回。不幸的是,由於應用程序體系結構,這是我現在唯一的選擇。展望未來,我認爲我會去讀取字符串的值,然後將其轉換爲十進制。 並感謝那篇文章。這是一個很棒的閱讀。 :) –

0

認真所有你需要做的就是這樣的事情...

object d = 0.39999999999999997; 
decimal result; 
decimal.TryParse(d.ToString(), out result); 
return result; 
+0

謝謝Sven的編輯 –