「double val = 1」との違いはありますか?そして「double val = 1D;」?


17

次の2つのコードに違いはありますか?

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;
    }

}

私たちのコードベースは2番目の記述方法を使用していることがわかりました。


私の頭の上で、最初の1つは、長くて2倍のプロモーションを含みます。
Tanveer Badar

2
最初は暗黙的にdoubleに変換され、2番目は変換されません。
Serkan Arslan、

2
質問のタイトルと本文の質問が一致せず、2つの質問の回答が異なります。
Eric Lippert

1
@Eric Lippert実際、質問の本文は他のユーザーによって編集されています。
srnldai

1
@ブライアン:いいえ、元のポスターは正しいです。編集によって質問の意味が変わったが、気づかなかった。もともとの質問は「違いはありますか…?さらに違いはあるのか...?」と強調しました。削除された「Further」は、元の投稿者が、答えが異なる可能性がある2つの質問をしていることに気付いたことを示しています。これは悪い習慣です。質問は、理想的には単一の質問をする必要があります。ただし、編集により、2つの質問は2つの異なる質問ではなく、同じ質問であることが意図されているように見えます。
Eric Lippert

回答:


18

ここに2つの質問があり、それらが異なる答えを持っていることに注意することが重要です。

間に差があるdouble val = 1;とはdouble val = 1D;

いいえ。C#コンパイラは、整数リテラルがdoubleが予期されるコンテキストで使用されている場合を認識し、コンパイル時に型を変更するため、これら2つのフラグメントは同じコードを生成します。

次の2つのコードに違いはありますか?

double Val; 
...    
this.Val = src ? 1 : 0;
---
this.Val = src ? 1D : 0D;

はい。整数定数は自動的倍に変更されていることをルールのみに適用された定数、およびsrc ? ...ない定数。コンパイラーは、次のように前者を生成します。

int t;
if (src)
  t = 1;
else
  t = 0;
this.Val = (double)t;

そして2番目は

double t;
if (src)
  t = 1D;
else
  t = 0D;
this.Val = t;

つまり、最初に整数を選択してそれをdoubleに変換し、2番目にdoubleを選択します。

参考:C#コンパイラまたはジッターは許可されます最初のプログラムは、第二に、最適化することができることを認識するために、それは実際にそうするかどうかは知りません。C#コンパイラリフトされた算術の変換を条件文の本体に移動することがあります。私はそのコードを8年ほど前に書いたが、詳細のすべてを思い出したわけではない。


6

そこ 生成されたILコードの違いは。

このクラス:

class Test1
{
    public readonly double Val;

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

コンストラクターのこのILコードを生成します。

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

そしてこのクラス:

class Test2
{
    public readonly double Val;

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

コンストラクターのこのILコードを生成します。

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

ご覧のとおり、最初のバージョンでは、 conv.r8、intをdoubleに変換する必要があります。

ただし、(1)最終結果は同じであり、(2)JITコンパイラはこれらの両方を同じマシンコードに変換する可能性があります。

だから答えは:はい、あります違いがありますが、心配する必要のある違いありません。

個人的には、プログラマーの意図をよりよく表し、非常にわずかに効率的なコードを生成する可能性があるため、2番目のバージョンを使用します(JITコンパイラーが何を実行するかによって異なります)。


4

違いはありません。コンパイラーは暗黙的に変換を行うか行わないかについて十分にスマートです。
ただし、を使用する場合は、変数がintではなくdoubleであることを確認するようvarに記述var val = 42D;する必要があります。

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 !! /!\
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.