С# Преобразование объекта в десятичный

Я пытаюсь преобразовать объект со значением 0.39999999999999997 в десятичную переменную без потери точности.

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, если это имеет значение.

Ответ 1

Я думаю, что это код, который вы ищете:

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);

Ответ 2

Для этого вам нужно будет назначить его аналогичным образом

object d = 0.39999999999999997M;

У объекта нет возможности поддерживать точность, если вы ее не заставляете. (Если это не настоящий код, вам нужно будет показать, как его назначили)

Только тогда что-то вроде этого будет работать decimal dec = Convert.ToDecimal(d);

Ответ 3

Когда вы читаете данные из базы данных (как вы отметили в одном из комментариев, IMO, вы должны добавить это в свой вопрос), я думаю, что это ужасная идея разрешить преобразование в двойное и обратное во время чтения из базы данных, потому что вы будет потерять точность [вероятно, он хранится как фиксированная точка или в числовой системе, которая может представлять десятичные числа]. Я думаю, что вы должны приложить некоторые усилия, чтобы прочитать сохраненные значения непосредственно в виде десятичных знаков (отредактируйте свою схему или что-то в этом роде), или если это невозможно, прочитайте их как строки и используйте Decimal.Parse() для получения фактических значений.

Фактически, ваш номер 0.39999999999999997 имеет 17 знаков после запятой, поэтому его нельзя сохранить как дважды безопасно.

P.S. Там отличная статья относительно .net. Партии и округление, написанные Джоном Скитом.

Ответ 4

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

Ответ 5

Decimal d = new Decimal(d);

если d является двойным, то согласно документации MSDN это должно сохранять точность.

Этот конструктор округляет значение до 15 значащих цифр с округлением до ближайшего. Это делается, даже если число содержит более 15 цифр, а менее значимые цифры - равны нулю.

Ответ 6

на этой странице 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
Таким образом, вы просто теряете свою точность без суффикса m.

Ответ 7

объект d = 0,399999999999999999999999997M; будет работать на вас.

Ответ 8

Серьезно все, что вам нужно сделать, это что-то вроде этого...

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