C # Преобразование объекта в десятичное - PullRequest
13 голосов
/ 27 июля 2011

Я пытаюсь преобразовать объект со значением 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, который не может сохранить это значение, как показано ниже.

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

Как преобразовать этот объект в десятичный без потери точности?

Я использую .NET Framework 3.5, если это имеет значение.

Ответы [ 8 ]

10 голосов
/ 27 июля 2011

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

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);
4 голосов
/ 27 июля 2011

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

object d = 0.39999999999999997M;

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

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

1 голос
/ 27 июля 2011

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

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

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

0 голосов
/ 18 июля 2016

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

object d = 0.39999999999999997; 
decimal result;
decimal.TryParse(d.ToString(), out result);
return result;
0 голосов
/ 27 июля 2011

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

0 голосов
/ 27 июля 2011

на этой странице 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.

0 голосов
/ 27 июля 2011

Decimal d = new Decimal(d);

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

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

0 голосов
/ 27 июля 2011
string val = "0.39999999999999997");
decimal d = decimal.Parse(val,
    System.Globalization.NumberStyles.AllowDecimalPoint);//0.39999999999999997
...