Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a difference between "double val = 1;" and "double val = 1D;"?

Tags:

c#

.net

Is there a difference between the following two pieces of code?

class Test {

    public readonly double Val;

    public Test(bool src) {
        this.Val = src ? 1 : 0;
    }

}

class Test {

    public readonly double Val;

    public Test(bool src) {
        this.Val = src ? 1D : 0D;
    }

}

I found that our code base uses the second way of writing.

like image 757
srnldai Avatar asked Nov 18 '19 14:11

srnldai


3 Answers

There are two questions here and it is important to note that they have different answers.

Is there a difference between double val = 1; and double 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.

like image 72
Eric Lippert Avatar answered Nov 18 '22 16:11

Eric Lippert


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).

like image 6
Matthew Watson Avatar answered Nov 18 '22 16:11

Matthew Watson


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 !! /!\
like image 4
Cid Avatar answered Nov 18 '22 15:11

Cid