Is there a difference between "double val = 1;" and "double val = 1D;"?
There are two questions here and it is important to note that they have different answers.
Is there a difference between
double val = 1;
anddouble val = 1D;
?
No. The C# compiler recognizes when an integer literal is used in a context where a double is expected and does the type change at compile time, so these two fragments will generate the same code.
Is there a difference between the following two pieces of code?
double Val;
...
this.Val = src ? 1 : 0;
---
this.Val = src ? 1D : 0D;
Yes. The rule that integer constants are automatically changed to doubles only applies to constants, and src ? ...
is not a constant. The compiler will generate the former as though you wrote:
int t;
if (src)
t = 1;
else
t = 0;
this.Val = (double)t;
And the second as
double t;
if (src)
t = 1D;
else
t = 0D;
this.Val = t;
That is, in the first we choose an integer and then convert it to double, and in the second we choose a double.
FYI: the C# compiler or the jitter are permitted to recognize that the first program can be optimized into the second, but I do not know if it actually does so. The C# compiler does sometimes move conversions for lifted arithmetic into the bodies of conditionals; I wrote that code some eight years ago now, but I do not recall all of the details.
There is a difference in the generated IL code.
This class:
class Test1
{
public readonly double Val;
public Test1(bool src)
{
this.Val = src ? 1 : 0;
}
}
Produces this IL code for the constructor:
.class private auto ansi beforefieldinit Demo.Test1
extends [mscorlib]System.Object
{
.field public initonly float64 Val
.method public hidebysig specialname rtspecialname instance void .ctor (
bool src
) cil managed
{
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldarg.1
IL_0008: brtrue.s IL_000d
IL_000a: ldc.i4.0
IL_000b: br.s IL_000e
IL_000d: ldc.i4.1
IL_000e: conv.r8
IL_000f: stfld float64 Demo.Test1::Val
IL_0014: ret
}
}
And this class:
class Test2
{
public readonly double Val;
public Test2(bool src)
{
this.Val = src ? 1d : 0d;
}
}
Produces this IL code for the constructor:
.class private auto ansi beforefieldinit Demo.Test2
extends [mscorlib]System.Object
{
.field public initonly float64 Val
.method public hidebysig specialname rtspecialname instance void .ctor (
bool src
) cil managed
{
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldarg.1
IL_0008: brtrue.s IL_0015
IL_000a: ldc.r8 0.0
IL_0013: br.s IL_001e
IL_0015: ldc.r8 1
IL_001e: stfld float64 Demo.Test2::Val
IL_0023: ret
}
}
As you can see, in the first version it has to call conv.r8
to convert an int to a double.
However: (1) The end result is identical and (2) the JIT compiler may well translate both of these to the same machine code.
So the answer is: Yes, there is a difference - but not one that you need to worry about.
Personally, I'd go for the second version since that better expresses the programmer's intent, and may produce very very slightly more efficient code (depending on what the JIT compiler gets up to).
There is no difference, the compiler is smart enough to implicitely do a conversion or not.
However, if you use var
, you need to write var val = 42D;
to make sure the variable is a double and not an int.
double foo = 1; // This is a double having the value 1
double bar = 1d; // This is a double having the value 1
var val = 42d; // This is a double having the value 42
var val2 = 42; // /!\ This is an int having the value 42 !! /!\