2011-07-27 44 views
10

Tôi đang cố chuyển đổi đối tượng có giá trị 0.39999999999999997 thành biến thập phân mà không làm mất độ chính xác.C# Chuyển đổi đối tượng thành số thập phân

object d = 0.39999999999999997; 

Tôi đã thử các phương pháp sau.

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 

Tôi biết đây không phải là vấn đề với kiểu dữ liệu thập phân không thể lưu trữ giá trị này như được minh họa bên dưới.

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

Làm cách nào để chuyển đổi đối tượng này sang thập phân mà không làm mất độ chính xác?

Tôi đang sử dụng .NET Framework 3.5 nếu vấn đề đó quan trọng.

+0

không phải là rất chắc chắn rằng bạn có thể đảm bảo độ chính xác persistant giữa boxing/unboxing và khác nhau chuyển đổi loại nổi. – Tigran

Trả lời

8

Tôi nghĩ rằng đây là mã bạn đang tìm kiếm:

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

Hoàn hảo. Mặc dù tôi lo ngại việc sử dụng đôi sẽ ảnh hưởng đến độ chính xác của dữ liệu, nhưng điều này có vẻ như là lựa chọn tốt nhất cho đến nay. Cảm ơn. –

+0

Trong trường hợp này, tôi đồng ý với bình luận của V4Vendettas: "Tôi sợ nó sẽ không thể thực hiện được vì đối tượng có tham chiếu đến giá trị và trong trường hợp của bạn trừ khi tham chiếu là số thập phân bạn không thể đạt được độ chính xác đó" – Reniuz

+0

Cảm ơn bạn. Lời giải thích tuyệt vời. :) –

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

'đối tượng d = 0.39999999999999997; double decim = double.Parse (d.ToString(), System.Globalization.NumberStyles.AllowDecimalPoint); // decim = 0.4' –

+0

@ Chathura: đó là lỗi đánh máy. Tôi có nghĩa là 'decima.Parse' tôi đã thử nghiệm nó và kết quả như mong đợi. –

+0

Hey chuỗi đã đi vào hình ảnh ở đâu? – V4Vendetta

0

Decimal d = new Decimal(d);

nếu d là một đôi, sau đó theo các tài liệu MSDN này nên giữ cho chính xác.

Hàm tạo này làm tròn giá trị thành 15 chữ số có nghĩa bằng cách làm tròn đến gần nhất. Điều này được thực hiện ngay cả khi số có nhiều hơn 15 chữ số và các chữ số ít quan trọng bằng không.

+0

Không hoạt động. Không thể truyền một đối tượng vào hàm tạo Decimal(). –

+0

.Net 4.0 và 3.5 đều có một hàm tạo với hai ... – Spence

0

trên trang này http://msdn.microsoft.com/en-us/library/364x0z75(v=vs.80).aspx nó được viết "Nếu không có hậu tố m, số lượng được coi là một đôi"
Và mã này

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

xuất hiện System.Double

trong khi điều này một

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

hiển thị System.Decimal
Vì vậy, bạn chỉ mất chính xác mà không có hậu tố m.

+0

Kiểu thập phân là cần thiết vì cách Double lưu trữ giá trị của nó, nó không lưu trữ giá trị chính xác mà tôi nhập. Ví dụ 12.03 sẽ được lưu trữ dưới dạng 12.029999999999999, v.v. –

4

Để làm việc này bạn sẽ cần phải gán nó tương tự

object d = 0.39999999999999997M; 

Không có cách nào cho đối tượng để duy trì độ chính xác trừ khi bạn buộc nó đến. (Nếu đây không phải là mã thực tế, bạn sẽ cần phải chứng minh như thế nào được giao)

Chỉ khi đó sẽ giống như thế này sẽ làm việc decimal dec = Convert.ToDecimal(d);

+0

Do cách biến này được khởi tạo (giá trị thực được lưu trữ trong cơ sở dữ liệu), tôi không biết cách nào sẽ là giá trị thập phân. –

+0

Nếu bạn sẽ sử dụng số thập phân tại sao không nhận được giá trị cơ sở dữ liệu và chuyển đổi nó thành số thập phân, vấn đề trong đó là gì? – V4Vendetta

+0

Hãy để tôi làm rõ. Đây là một phương pháp chung chấp nhận các đối tượng. Và tôi không thể thay đổi chữ ký phương thức. –

0

đối tượng d = 0.399999999999999999999999997M; sẽ hoạt động.

+0

Không phải tùy chọn. Giá trị thực được lấy từ cơ sở dữ liệu. –

1

Khi bạn đang đọc dữ liệu từ cơ sở dữ liệu (như bạn đã nêu trong một trong những ý kiến, IMO bạn nên nói thêm rằng trong câu hỏi của bạn) Tôi nghĩ đó là một ý tưởng tồi tệ để cho phép chuyển đổi thành gấp đôi và ngược lại trong khi đọc từ cơ sở dữ liệu, bởi vì bạn sẽ mất độ chính xác [khả năng nó được lưu trữ dưới dạng điểm cố định hoặc trong một hệ thống số có thể biểu diễn số thập phân]. Tôi nghĩ rằng bạn phải nỗ lực để đọc các giá trị được lưu trữ trực tiếp dưới dạng thập phân (chỉnh sửa giản đồ của bạn hoặc thứ gì đó tương tự) hoặc nếu không thể, hãy đọc chúng dưới dạng chuỗi và sử dụng Decimal.Parse() để nhận giá trị thực .

Thực ra, số của bạn 0.39999999999999997 có 17 chữ số thập phân vì vậy không thể lưu trữ an toàn gấp đôi.

P.S. Có a great article liên quan đến .net Đôi và làm tròn được viết bởi Jon Skeet.

+0

Tôi biết đó là một ý tưởng tồi để chuyển đổi thành gấp đôi và quay lại. Thật không may đó là lựa chọn duy nhất tôi có ngay bây giờ vì kiến ​​trúc ứng dụng. Về sau, tôi nghĩ tôi sẽ đọc các giá trị dưới dạng chuỗi và sau đó chuyển đổi nó thành Thập phân. Và cảm ơn bài viết đó. Thật là một buổi đọc tuyệt vời. :) –

0

Nghiêm túc tất cả các bạn phải làm là một cái gì đó như thế này ...

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

Cảm ơn Sven đã chỉnh sửa –

Các vấn đề liên quan