Преобразование двойной переменной в десятичную

96

Как привести doubleк decimalкоторому используется при разработке валюты. Куда Mдеваться?

decimal dtot = (decimal)(doubleTotal);
Фло
источник

Ответы:

85

Вы используете только Mдля числового литерала, когда вы приводите его просто:

decimal dtot = (decimal)doubleTotal;

Обратите внимание, что число с плавающей запятой не подходит для сохранения точного значения, поэтому, если вы сначала сложите числа, а затем конвертируете в, Decimalвы можете получить ошибки округления. Возможно, вы захотите преобразовать числа в, Decimalпрежде чем складывать их вместе, или убедитесь, что числа не являются числами с плавающей запятой.

Гуффа
источник
В качестве дополнительного вопроса, зачем требуется явное преобразование? Я пробовал это и получаю сообщение об ошибке, что двойное число не может быть явно преобразовано в десятичное число, но разве десятичное число не имеет большей точности? (то есть так же, как приведение типа int к double может быть неявным.)
4
@Cortana: точность десятичной дроби выше, но диапазон меньше. Двойное значение может быть вне допустимого диапазона для десятичной дроби. См .: stackoverflow.com/questions/7817866/…
Guffa
41

Вы можете преобразовать двойное число в десятичное, как это, без Mбуквального суффикса:

double dbl = 1.2345D;
decimal dec = (decimal) dbl;

Вы должны использовать Mпри объявлении нового буквального десятичного значения:

decimal dec = 123.45M;

(Без Mсимвола 123.45 считается двойным и не компилируется.)

Крис Фулстоу
источник
28

использовать класс преобразования по умолчанию: Convert.ToDecimal(Double)

Тимур Садыков
источник
1
Нет, потому что это вызовет исключение OverflowException double vol_y = (double) Decimal.MaxValue + 10E + 28D; Console.WriteLine ("Convert.ToDecimal (vol_y) =" + Convert.ToDecimal (vol_y));
ToXinE 01
2
@ToXinE ИМХО, в большинстве случаев OverflowException лучше, чем
тихое
16
Convert.ToDecimal(the double you are trying to convert);
Том
источник
2
Я узнал, что класс Convert намного более гибкий и безопасный, чем приведение в C #.
Том
3
"Безопасно"? например, когда он не может выполнить приведение, он генерирует исключение во время выполнения вместо ошибки компилятора? Меня это так много раз кусало, что я активно избегаю Convert ...
Питер Ричи,
8
Поток @PeterRitchie немного устарел, но следует сказать: вызов метода Convert напрямую был бы более подходящим подходом. Может быть, я просто помешан на оптимизации, но на одну инструкцию меньше - это бонус (поскольку использование явного синтаксиса преобразования типа (Type) - это просто перегрузка оператора, вызывающая Convert).
Майк Джонсон
2
@PeterRitchie: С точки зрения языкового дизайна было бы лучше потребовать от программиста использовать один из двух методов преобразования, а не разрешать приведение типов из doubleв decimal, учитывая, что для doubleзначения вроде (1000000.0 / 3.0) в некоторых случаях это было бы хотите обрезать "лишнюю" точность, получая 333333.333333333D, но в других случаях нужно сохранить ее, давая 333333.333333333313931D. Вместо того, чтобы просто говорить «преобразовать в десятичное», код должен указывать, как это преобразование должно выполняться.
supercat
2
@supercat, который действительно кажется не связанным с моим первым комментарием, потому что использование Convert.ToDecimal(double)такое же, как (decimal)doubleTotal, за исключением того, что если doubleTotalвы измените его на другой тип, вы, вероятно, избежите ошибки времени компиляции и представите ошибку времени выполнения, которую труднее найти, потому что другой ToDecimal может быть вызвано переопределение. Оператор приведения более явный ...
Питер Ричи
1

Что ж, это старый вопрос, и я действительно использовал некоторые из представленных здесь ответов. Тем не менее, в моем конкретном сценарии было возможно, что doubleзначение, которое я хотел преобразовать, decimalчасто было больше, чем decimal.MaxValue. Итак, вместо обработки исключений я написал этот метод расширения:

    public static decimal ToDecimal(this double @double) => 
        @double > (double) decimal.MaxValue ? decimal.MaxValue : (decimal) @double;

Вышеупомянутый подход работает, если вы не хотите беспокоиться об обработке исключений переполнения, и если такое произойдет, вы хотите просто сохранить максимально возможное значение (мой случай), но я знаю, что для многих других сценариев это не будет ожидаемым поведением и, возможно, потребуется обработка исключений.

такион
источник
1
Это не сработает в следующем случае double _double = (double) decimal.MaxValue; Я бы предложил использовать> = в сравнении публичного статического десятичного числа ToDecimal (this double _double) => _double> = (double) decimal.MaxValue? decimal.MaxValue: (десятичный) _double;
Мартин Эйлз