web-dev-qa-db-ja.com

x = x +1対x + = 1

これらの2つのコマンドは同じ目的、つまりXを1ずつインクリメントする結果になりますが、おそらく後者の方が効率的であるという印象を受けます。

これが正しくない場合は、差分を説明してください。

それが正しければ、なぜ後者がより効率的である必要がありますか?両方とも同じILにコンパイルするべきではありませんか?

ありがとう。

30
ChadD

+ =のMSDNライブラリ から:

この演算子を使用することは、結果が1回だけ評価されることを除いて、result = result + expressionを指定することとほとんど同じです。

したがって、それらは同一ではなく、それがx + = 1がより効率的である理由です。

更新:MSDNライブラリのリンクが VBページ ではなくJScriptページにあることに気づきました。同じ引用。

したがって、さらに調査およびテストした結果、その回答はVB.NETには適用されません。私は間違っていた。これがサンプルコンソールアプリです:

Module Module1

Sub Main()
    Dim x = 0
    Console.WriteLine(PlusEqual1(x))
    Console.WriteLine(Add1(x))
    Console.WriteLine(PlusEqual2(x))
    Console.WriteLine(Add2(x))
    Console.ReadLine()
End Sub

Public Function PlusEqual1(ByVal x As Integer) As Integer
    x += 1
    Return x
End Function

Public Function Add1(ByVal x As Integer) As Integer
    x = x + 1
    Return x
End Function

Public Function PlusEqual2(ByVal x As Integer) As Integer
    x += 2
    Return x
End Function

Public Function Add2(ByVal x As Integer) As Integer
    x = x + 2
    Return x
End Function

End Module

PlusEqual1とAdd1の両方のILは実際に同一です。

.method public static int32 Add1(int32 x) cil managed
{
.maxstack 2
.locals init (
    [0] int32 Add1)
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldc.i4.1 
L_0003: add.ovf 
L_0004: starg.s x
L_0006: ldarg.0 
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 
}

PlusEqual2とAdd2のILも、ほぼ同じです。

.method public static int32 Add2(int32 x) cil managed
{ 
.maxstack 2
.locals init (
    [0] int32 Add2)
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldc.i4.2 
L_0003: add.ovf 
L_0004: starg.s x
L_0006: ldarg.0 
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 
}
107
CoderDennis

簡単なコンソールアプリを作成しました。

static void Main(string[] args)
{
    int i = 0;
    i += 1;
    i = i + 1;
    Console.WriteLine(i);
}

私はReflectorを使用してそれを分解しました、そしてこれが私が得たものです:

private static void Main(string[] args)
{
    int i = 0;
    i++;
    i++;
    Console.WriteLine(i);
}

それらは同じです。

それらは同じようにコンパイルされ、2番目は入力が簡単です。

18
z -

重要:

評価を指定する答えは、一般的な言語で+=が行うことに関して確かに正しいです。しかし、VB.NETでは、OPで指定されたXは変数またはプロパティであると想定しています。


それらはおそらく同じILにコンパイルされます。

更新(おそらく論争に対処するため):

VB.NETは、プログラミング言語の仕様です。仕様で定義されているものに準拠するコンパイラは、VB.NET実装にすることができます。 MS VB.NETコンパイラのソースコードを編集して、X += 1の場合のくだらないコードを生成する場合でも、VB.NET仕様に準拠します(動作方法については何も述べられていないため)。効果はまったく同じであると言っているだけなので、同じコードを生成するのは論理的です)。

コンパイラーは両方に対して同じコードを生成する可能性が非常に高いですが(実際にそう感じています)、それはかなり複雑なソフトウェアです。ちなみに、同じコードが2回コンパイルされたときに、コンパイラがまったく同じコードを生成することを保証することすらできません。

(コンパイラのソースコードを熟知していない限り)100%安全だと感じることができるのは、優れたコンパイラは同じコード、パフォーマンス面でを生成する必要があるということです。 まったく同じコード

11
Mehrdad Afshari

非常に多くの憶測!リフレクターは分解しながら最適化できるため、リフレクターの結論でさえ必ずしも真実ではありません。

では、なぜ皆さんは誰もILコードを調べていないのですか?次のC#プログラムをご覧ください。

_static void Main(string[] args)
{
    int x = 2;
    int y = 3;
    x += 1;
    y = y + 1;
    Console.WriteLine(x);
    Console.WriteLine(y);
}
_

このコードスニペットは次のようにコンパイルされます。

.method private hidebysig static void Main(string[] args) cil managed
_{_
_.entrypoint_
// Code size 25 (0x19)
_.maxstack 2_
_.locals init ([0] int32 x,_
_[1] int32 y)_
_// some commands omitted here_

_IL_0004: ldloc.0_
_IL_0005: ldc.i4.1_
_IL_0006: add_
_IL_0007: stloc.0_

_IL_0008: ldloc.1_
_IL_0009: ldc.i4.1_
_IL_000a: add_
_IL_000b: stloc.1_

_// some commands omitted here_
_}_

ご覧のとおり、実際にはまったく同じです。そして、それはなぜですか? ILの目的は、方法ではなく、何をすべきかを伝えることだからです。最適化はJITコンパイラの仕事になります。ところで、それはVB.Netでも同じです

8
BlackStar

X86では、xがレジスタeaxにある場合、両方とも次のようになります。

株式会社eax;

つまり、コンパイル段階の後、ILは同じになります。

「オプティマイザーを信頼する」で答えることができるこのような質問のクラス全体があります。

有名な神話は
x ++;
はより効率が悪い
++ x;
一時的な値を格納する必要があるため。一時的な値を使用しない場合、オプティマイザはそのストアを削除します。

4
Drew Hoskins

それらはVBでも同じかもしれません。それらはC(演算子の由来)で必ずしも同じではありません。

2
Paul Sonier
  1. はい、同じように動作します。
  2. いいえ、おそらく同じくらい効率的です。オプティマイザーはそのようなことを上手にしています。再確認したい場合は、最適化されたコードを記述して、リフレクターで表示してください。
2
Greg D

Xがintやfloatのような単純な型である場合、オプティマイザーはおそらく同じ結果を生成します。

他の言語を使用する場合(ここでは限られたVB知識、+ =?をオーバーロードできますか?)、xは1つの大きなホーンオブジェクトになる可能性があり、前者は追加のコピーを作成し、数百になる可能性があります後者はそうではありません。

2
Macke

同じだ。

x=x+1 

数学的に矛盾が見られますが、

x+=1

そうではなく、入力するのは軽いです。

2
Luixv

C++では、データ型がxであり、演算子がどのように定義されているかによって異なります。 xがクラスのインスタンスである場合、まったく異なる結果を得ることができます。

または、質問を修正して、xが整数などであることを指定する必要があります。

1
Milan Babuškov

違いはメモリ参照に使用される追加のクロックサイクルによるものだと思いましたが、間違っていることがわかりました。自分では理解できない

instruction type        example                      cycles

================================================== =================

ADD reg,reg             add ax,bx                       1
ADD mem,reg             add total, cx                   3
ADD reg,mem             add cx,incr                     2
ADD reg,immed           add bx,6                        1
ADD mem,immed           add pointers[bx][si],6          3
ADD accum,immed         add ax,10                       1

INC reg                 inc bx                          1
INC mem                 inc vpage                       3

MOV reg,reg             mov bp,sp                       1
MOV mem,reg             mov array[di],bx                1
MOV reg,mem             mov bx,pointer                  1
MOV mem,immed           mov [bx],15                     1
MOV reg,immed           mov cx,256                      1
MOV mem,accum           mov total,ax                    1
MOV accum,mem           mov al,string                   1
MOV segreg,reg16        mov ds,ax                       2, 3
MOV segreg,mem16        mov es,psp                      2, 3
MOV reg16,segreg        mov ax,ds                       1
MOV mem16,segreg        mov stack_save,ss               1
MOV reg32,controlreg    mov eax,cr0                     22
                        mov eax,cr2                     12
                        mov eax,cr3                     21, 46
                        mov eax,cr4                     14
MOV controlreg,reg32    mov cr0,eax                     4
MOV reg32,debugreg      mov edx,dr0                     DR0-DR3,DR6,DR7=11;
                                                        DR4,DR5=12 
MOV debugreg,reg32      mov dr0,ecx                     DR0-DR3,DR6,DR7=11;
                                                        DR4,DR5=12 

ソース: http://turkish_rational.tripod.com/trdos/pentium.txt

指示は次のように翻訳される場合があります。

;for i = i+1   ; cycles
mov  ax,   [i]  ; 1
add  ax,   1    ; 1
mov  [i],  ax   ; 1

;for i += 1
; dunno the syntax of instruction. it should be the pointers one :S     

;for i++
inc  i          ; 3
;or
mov  ax,   [i]  ; 1
inc  ax         ; 1
mov  [i],  ax   ; 1

;for ++i
mov  ax,   [i]  ; 1
;do  stuff      ; matters not
inc  ax         ; 1
mov  [i],  ax   ; 1

すべて同じであることが判明しました:Sそれは役に立つかもしれないほんの一部のデータです。コメントしてください!

1
xenodevil

注目に値するのは、+ =、-=、* =などが暗黙的なキャストを行うことです。

int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.
1
Peter Lawrey

Xが単純な整数スカラー変数の場合、それらは同じである必要があります。

Xが大きな式であり、おそらく副作用がある場合、+=1および++は2倍の速さである必要があります。

多くの人は、あたかもそれが最適化のすべてであるかのように、この種の低レベルの最適化に集中します。私はあなたがそれがはるかに大きな主題であることを知っていると思います。

0
Mike Dunlavey

実行時には(少なくともPerlでは)違いはありません。 x + = 1は、x = x +1よりも入力が約0.5秒速くなります。

0
Brian

プログラムの効率に違いはありません。タイピングの効率だけ。

0
Andrew Ensley

1980年代初頭、Lattice Cコンパイラの非常に優れた最適化の1つは、「x = x + 1;」、「x + = 1;」でした。および「x ++;」すべてがまったく同じマシンコードを生成しました。彼らがそれを行うことができれば、この千年紀で書かれたコンパイラは間違いなくそれを行うことができるはずです。

0
Paul Tomblin