2015-02-10 2 views
1

Я понимаю, что decimal - это формат чисел, подходящий для финансов и денег в целом, поскольку он имеет фиксированную точность.Поскольку операция «десятичная» * «десятичная» приводит к потере точности, но разрешена, почему операция «десятичная» * «двойная» запрещена?

Таким образом, при добавлении или вычитании двух decimals, никогда не может быть потери точности.

Учитывая это, я могу понять, что операция 'decimal' + 'double' должна быть запрещена компилятором, так как может быть потеря точности.

Но что происходит, когда вы умножаете (или разделяете) два decimals?

Давайте рассмотрим простой десятичный тип, всего 4 цифры и 2 цифры точности после десятичной точки (с 00.00 до 99.99).

Вы можете определить a = 0.01

Тогда m = a * a = 0.0001, усеченный до 0.00 так происходит потеря точности.

Несмотря на потерю точности, эта операция считается законной компилятором.

Итак, мы имеем следующие случаи в C#:

  • decimal/int: правовые, несмотря на потерю точности
  • decimal/decimal: правовые, несмотря на потерю точности
  • decimal * decimal: правовые, несмотря на потери точности
  • decimal * double : незаконный

(Of co urse, вы всегда можете переопределить литой, но это решение не удовлетворяет меня.)

Есть ли другая причина, по которой я не знаю, чтобы объяснить это?

Если вы имеете дело с процентной ставкой или ставкой НДС или ставками в целом, мне будет более логично использовать двойной для хранения этих значений, а затем иметь возможность использовать их с десятичной точкой. Но я должен выбирать между:

  • хранения скорости с decimal (излишним).
  • хранение ставки с помощью double, затем литье (уродливое).

Со всем, что в виду, мой вопрос:

Есть ли причина, почему «decimal» * «double» запрещен C# компилятор?

ответ

1

decimal multiplication (*) operatorтолько принимает операнды типа decimal. Тем не менее, есть неявный литой от int до decimal, поэтому компилятор передает int в decimal для вас.

не

Techncially, не существует неявное приведение от decimal к double (или наоборот, так что компилятор не может бросить вас, вы должны явно привести один из операндов

Логически. , вам нужно сделать бросок на последнем, потому что компилятор должен знать, что такое результат .Для первых трех тип ясен - все они приводят к decimal из-за неявного литья с int до decimal.

Но что должно быть результатом decimal * double be? Это может быть либо decimal, либо double в зависимости от ваших потребностей. Если вы назначаете его переменной, то компилятор может вывести, но что делать, если это сделано inline? Каким будет тип m * a + 1?

Значит, вам нужен актерский состав, чтобы сообщить компилятору, что такое результирующий тип.

Когда имеешь дело с процентной ставкой, или ставкой НДС, или ставки в целом, казалось бы, больше логики для меня, чтобы использовать двойной хранить эти значения

Почему? Зачем вам хранить процентную ставку 0,10 в типе, который не может хранить 0.10 точно?

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

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

+0

Hm, на самом деле это 'var s = (double) (12.4m * 23.3d);' также запрещено, хотя и дается результат. Я думаю, что речь идет о том, чтобы компилятор просто __how__ выполнял вычисления. – TaW

+2

@TaW, что более вероятно из-за подвыражения '(12.4m * 23.3d)' неспособности по причине, приведенной в этом ответе – AlexFoxGill

+0

Спасибо за подробный ответ. Что касается ставок, которые я хотел бы хранить, это могут быть такие вещи, как «1/3 = 0,3333 ...», которые могут храниться точно с десятичной или двойной. – Fumidu