What is the difference between "decimal.Divide" and the traditional "/" in C #?

8
decimal a = 10/5;

Returns 2

decimal b = decimal.Divide(10,5);

Returns 2

    
asked by anonymous 26.04.2016 / 23:45

3 answers

7

None practice, it's just a different syntactic form, they perform exactly the same thing. At least if we are only talking about this specific example or use with decimals.

See the operator source . Documentation .

    public static Decimal operator /(Decimal d1, Decimal d2) {
        FCallDivide (ref d1, ref d2);
        return d1;
    }

IL code generated using the operator:

.maxstack  4
.locals init (valuetype [mscorlib]System.Decimal V_0)
IL_0000:  nop
IL_0001:  ldsfld     int32 Program::x
IL_0006:  ldsfld     int32 Program::y
IL_000b:  div
IL_000c:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int32)
IL_0011:  stloc.0
IL_0012:  ldstr      "{0} / {1} = {2}"
IL_0017:  ldsfld     int32 Program::x
IL_001c:  box        [mscorlib]System.Int32
IL_0021:  ldsfld     int32 Program::y
IL_0026:  box        [mscorlib]System.Int32
IL_002b:  ldloc.0
IL_002c:  box        [mscorlib]System.Decimal
IL_0031:  call       string [mscorlib]System.String::Format(string,
                                                            object,
                                                            object,
                                                            object)
IL_0036:  call       void [mscorlib]System.Console::WriteLine(string)
IL_003b:  nop
IL_003c:  call       void Program::Teste()
IL_0041:  nop
IL_0042:  ret

Now let's use decimal values as operands:

.maxstack  4
.locals init (valuetype [mscorlib]System.Decimal V_0)
IL_0000:  nop
IL_0001:  ldsfld     valuetype [mscorlib]System.Decimal Program::x
IL_0006:  ldsfld     valuetype [mscorlib]System.Decimal Program::y
IL_000b:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Division(valuetype [mscorlib]System.Decimal,
                                                                                              valuetype [mscorlib]System.Decimal)
IL_0010:  stloc.0
IL_0011:  ldstr      "{0} / {1} = {2}"
IL_0016:  ldsfld     valuetype [mscorlib]System.Decimal Program::x
IL_001b:  box        [mscorlib]System.Decimal
IL_0020:  ldsfld     valuetype [mscorlib]System.Decimal Program::y
IL_0025:  box        [mscorlib]System.Decimal
IL_002a:  ldloc.0
IL_002b:  box        [mscorlib]System.Decimal
IL_0030:  call       string [mscorlib]System.String::Format(string,
                                                            object,
                                                            object,
                                                            object)
IL_0035:  call       void [mscorlib]System.Console::WriteLine(string)
IL_003a:  nop
IL_003b:  call       void Program::Teste()
IL_0040:  nop
IL_0041:  ret

See the method font . Documentation

    public static Decimal Divide(Decimal d1, Decimal d2)
    {
        FCallDivide (ref d1, ref d2);
        return d1;
    }

IL code generated:

.maxstack  4
.locals init (valuetype [mscorlib]System.Decimal V_0)
IL_0000:  nop
IL_0001:  ldsfld     int32 Program::x
IL_0006:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int32)
IL_000b:  ldsfld     int32 Program::y
IL_0010:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int32)
IL_0015:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::Divide(valuetype [mscorlib]System.Decimal,
                                                                                         valuetype [mscorlib]System.Decimal)
IL_001a:  stloc.0
IL_001b:  ldstr      "{0} Divide {1} = {2}"
IL_0020:  ldsfld     int32 Program::x
IL_0025:  box        [mscorlib]System.Int32
IL_002a:  ldsfld     int32 Program::y
IL_002f:  box        [mscorlib]System.Int32
IL_0034:  ldloc.0
IL_0035:  box        [mscorlib]System.Decimal
IL_003a:  call       string [mscorlib]System.String::Format(string,
                                                            object,
                                                            object,
                                                            object)
IL_003f:  call       void [mscorlib]System.Console::WriteLine(string)
IL_0044:  nop
IL_0045:  ret

Now let's use decimal values as operands:

.maxstack  4
.locals init (valuetype [mscorlib]System.Decimal V_0)
IL_0000:  nop
IL_0001:  ldsfld     valuetype [mscorlib]System.Decimal Program::x
IL_0006:  ldsfld     valuetype [mscorlib]System.Decimal Program::y
IL_000b:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::Divide(valuetype [mscorlib]System.Decimal,
                                                                                         valuetype [mscorlib]System.Decimal)
IL_0010:  stloc.0
IL_0011:  ldstr      "{0} Divide {1} = {2}"
IL_0016:  ldsfld     valuetype [mscorlib]System.Decimal Program::x
IL_001b:  box        [mscorlib]System.Decimal
IL_0020:  ldsfld     valuetype [mscorlib]System.Decimal Program::y
IL_0025:  box        [mscorlib]System.Decimal
IL_002a:  ldloc.0
IL_002b:  box        [mscorlib]System.Decimal
IL_0030:  call       string [mscorlib]System.String::Format(string,
                                                            object,
                                                            object,
                                                            object)
IL_0035:  call       void [mscorlib]System.Console::WriteLine(string)
IL_003a:  nop
IL_003b:  ret

Note that both are static methods (even if one is syntactically an operator). Both accept overhead, but these do not have. None is overwritten. Both have the same parameters, and the same return. Both use the same upcast system implicit in the parameters / operands, after all cast is an independent operation. Then the promotion of other types occur in both. They generate the same exceptions.

Note that it ends up being the same. The compiler optimizes both for the same code.

I've obviously used variables that the compiler can not optimize to simulate actual usage. With literals you can generate different code for some compiler deficiency that I could not explain. The use of variables is the common case. Testing without context can be tricky. In an effort to avoid contaminating the test object with other effects, we often compare things that would not really happen in real-code usage. View the code used in dotNetFiddle .

There are differences

There is a difference in the code generated between the operator and the method. There is also a difference when the arguments are of the decimal type and not integers.

It is noticed that integer division is done natively (it will use processor instructions for integers) and then a type promotion will occur with the result. With the division promotion already occurs with method arguments.

With the use of decimal arguments there is no promotion and you can notice that two methods are called, one doing the operator ( op_Division() ) and the other is the obvious.

Precisely because of this difference, the results may be different when the division is not accurate when integer values are used. The same does not happen when values are decimal . One of the reasons for using the method is to ensure that the promotion takes place. Of course this is possible with the operator. There it has to be implicit:

decimal a = (decimal)10 / (decimal)5;

Here p IL is the same as the division made only with decimals.

Conclusion

If the doubt is only about the difference between using the operator or the method, which was my first interpretation, the difference is purely syntactic.

If the intention of the question is to consider what happens in case the operands are integers, there is a fundamental difference in the result (value found and performance that may not be so negligible), since it is a totally different operation that will be executed.

If the intention was to compare these exact codes, the first is doing a division of integers and promoting the result to decimal and the second makes promotion of integers to decimals and makes a division of decimals.

    
26.04.2016 / 23:52
5

The answers of bigown and Gypsy Morrison Mendez are correct, pointing out the differences of methods for operators. But in this specific example, there is no difference (*) - the variables a and b will have the value 2 (decimal). How the value was calculated is that it is a bit different.

In the first case (% w / o%), the integer values 10 and 5 are divided, resulting in the integer value 2. This value is then converted to the decimal type, and assigned to the decimal a = 10/5; variable.

In the second case ( a ), integer values 10 and 5 are converted to type decimal , and then the decimal b = decimal.Divide(10,5); method is called, with return value 2 (< strong> decimal ) is assigned to the variable decimal.Divide (**).

That is, the two methods took different paths to achieve the same result. If you had two integers whose division was not exact (eg, b ), the result would be different.

(*) Okay, technically there is a difference, but it does not affect the result; if it has any performance differences it will be negligible.

(**) In fact, if you have the constants decimal c = 10 / 3; and 10 in the first case, the compiler will probably be smart enough and do that operation directly, and that operation will be equivalent to 5 .

    
27.04.2016 / 01:20
3

/ is an operator . Decimal.Divide a method.

  • An operator accepts overload; a method accepts polymorphism. The concepts are different;
  • An operator has several return types; a method has some, depending on the signature of the method used. In the case of your operation, the numbers are not exactly decimal. They can be integers, but the compiler infers that they are decimal by their declaration;
  • Although the return is the same, Decimal.Divide is a much more restrictive (and, therefore, more suitable for strong typing) than the division operator, which needs to intuit the return type according to the operators.
26.04.2016 / 23:53