Десятичные и математические операции

У меня есть простое преобразование a decimal в С#. Это выглядит так:

private decimal BaseValue
{
    get; set;
}

public decimal ConvertedValue 
{
    get
    {
        return BaseValue * (365 / 360);
    }
}

Однако это не работает. Я предполагаю, что С# обрабатывает числа во фракции как целые числа. Поэтому я могу сделать это (что работает):

public decimal ConvertedValue 
{
    get
    {
        return BaseValue * (decimal)((double)365 / (double)360);
    }
}

Теперь это похоже на перебор, но я могу жить с этим. Мой основной вопрос:

Почему Visual Studio предупреждает меня, что "Cast избыточен", для (double) cast? И если я удаляю листинг (double), то приведение (decimal) становится излишним. И если я удалю это, я вернусь к решению, которое не сработает. Помощь...?

Ответы

Ответ 1

один из способов решения этого вопроса - указать, что числа в вычислении decimal с m в конце

return BaseValue * (365m / 360m);

Почему Visual Studio предупреждает меня, что "Cast is redundant", для (двойного) литья

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

(double)365 / (double)360

посмотрите документацию о перегрузках * оператора. Вы увидите, что операнды всегда одного типа:

decimal operator *(decimal x, decimal y);


... тогда (десятичная) литье становится излишней.

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

BaseValue * (decimal)(365 / 360)

Проблема здесь в области! вы отбрасываете весь результат деления на decimal. На самом деле вы могли бы решить свою проблему просто, удалив круглые скобки:

return BaseValue * 365 / 360;

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

Примечание: Удаление скобок в общем случае не совпадает с тем, что их оставляют. В некоторых случаях операции с плавающей запятой отличаются результатом, когда порядок таких операций изменяется, хотя оба выражения математически идентичны. Комментарий Banex

EDIT:

Элемент m называется литералом. Более подробную информацию о всех типах суффиксов или литералов можно найти в документации здесь

Ответ 2

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

Один из двух прикладов double избыточен, потому что, когда вы накладываете один из int на a double, ясно, что вы используете оператор деления double вместо целочисленное деление.

Но этого достаточно, чтобы просто использовать буквенный суффикс decimal m:

return BaseValue * (365m / 360);

Опять же, одного m достаточно, чтобы вывести правильный оператор.


Но hey, BaseValue уже есть decimal, и скобка не имеет смысла (если вы не хотите целочисленного divivsion)... это тоже должно работать:

return BaseValue * 365 / 360;

Ответ 3

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

return BaseValue * (365 / 360m);

Ответ 4

используйте суффикс m:

return 365m/360 * BaseValue;

Ответ 5

Существуют некоторые суффиксы для некоторых типов чисел, например:

 // Use long suffix.
 long l1 = 10000L;

 // Use double suffix.
 double d1 = 123.764D;

 // Use float suffix.
 float f1 = 100.50F;

 // Use unsigned suffix.
 uint u1 = 1000U;

 // Use decimal suffix.
 decimal m2 = 4000.1234M;

 // Use unsigned suffix and long suffix.
 ulong u2 = 10002000300040005000UL;

Суффиксы указывают типы номеров. Они инструктируют компилятор С#, что интегральный литерал, такой как 1000, считается определенным типом числа, например длинным (1000L). Мы рассмотрим, как добавить числовые суффиксы в числа.

В вашем случае:

public decimal ConvertedValue 
{
    get
    {
        return BaseValue * (365 / 360M);
    }
}

А также более понятно, когда вы используете суффиксы Uppercase:

Нижеследующие суффиксы. Вы также можете указать строчные суффиксы, такие как u, l, ul, f, d и m. Но их легче путать с числами. Буква "l" иногда рассматривается как номер 1.

Ответ 6

Вам нужна только одна двойная броска. Итак,

return BaseValue * (decimal)(365/(double)360);

будет работать нормально.

Как только один является двойным, компилятор знает, как рассматривать его как нецелое деление.

Альтернативно

return (BaseValue*365)/360;

будет работать.

или даже

return BaseValue*365/360;

поскольку умножение имеет более высокий приоритет, чем деление.

Ответ 7

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

public decimal ConvertedValue 
{
    get
    {
        return BaseValue * (365m/360);
    }
}

Причина, по которой второй листинг является избыточным, заключается в том, что С# выводит, что первое число (365) в вашем выражении ((double)365 / (double)360) равно double. Поэтому, чтобы вычислить деление, он будет трансформировать второй элемент в double. Поэтому неважно, напишите ли вы (double) как второй элемент:

csharp> (double) 365/350        
1.04285714285714                
csharp> (double) 365/ (double) 350
1.04285714285714

Тем не менее, совершенно бесполезно приводить к удвоениям, а затем вернуться к десятичным знакам. Используя один десятичный литерал в вашем выражении, другой номер также будет десятичным, и, таким образом, мы останемся в мире decimal.

Ответ 8

В вашем примере вы можете просто оставить скобки прочь:

return BaseValue*365/360;

Ответ 9

Двойник, разделенный на двойной, (конечно) двойной. Таким образом, литье результата является избыточным.

Было бы короче, если бы вы просто указали числа как десятичные числа:

 return BaseValue * (365m /360);

Ответ 10

Либо одна из (двойных) бросок избыточна, но не обе. Если любой аргумент операции двойной, другой аргумент автоматически преобразуется в double. Можете ли вы написать один из аргументов как константу реального числа, например, 365.0?