これらの2つのコマンドは同じ目的、つまりXを1ずつインクリメントする結果になりますが、おそらく後者の方が効率的であるという印象を受けます。
これが正しくない場合は、差分を説明してください。
それが正しければ、なぜ後者がより効率的である必要がありますか?両方とも同じILにコンパイルするべきではありませんか?
ありがとう。
+ =の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
}
簡単なコンソールアプリを作成しました。
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番目は入力が簡単です。
評価を指定する答えは、一般的な言語で+=
が行うことに関して確かに正しいです。しかし、VB.NETでは、OPで指定されたX
は変数またはプロパティであると想定しています。
それらはおそらく同じILにコンパイルされます。
VB.NETは、プログラミング言語の仕様です。仕様で定義されているものに準拠するコンパイラは、VB.NET実装にすることができます。 MS VB.NETコンパイラのソースコードを編集して、X += 1
の場合のくだらないコードを生成する場合でも、VB.NET仕様に準拠します(動作方法については何も述べられていないため)。効果はまったく同じであると言っているだけなので、同じコードを生成するのは論理的です)。
コンパイラーは両方に対して同じコードを生成する可能性が非常に高いですが(実際にそう感じています)、それはかなり複雑なソフトウェアです。ちなみに、同じコードが2回コンパイルされたときに、コンパイラがまったく同じコードを生成することを保証することすらできません。
(コンパイラのソースコードを熟知していない限り)100%安全だと感じることができるのは、優れたコンパイラは同じコード、パフォーマンス面でを生成する必要があるということです。 まったく同じコード。
非常に多くの憶測!リフレクターは分解しながら最適化できるため、リフレクターの結論でさえ必ずしも真実ではありません。
では、なぜ皆さんは誰も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でも同じです
X86では、xがレジスタeaxにある場合、両方とも次のようになります。
株式会社eax;
つまり、コンパイル段階の後、ILは同じになります。
「オプティマイザーを信頼する」で答えることができるこのような質問のクラス全体があります。
有名な神話は
x ++;
はより効率が悪い
++ x;
一時的な値を格納する必要があるため。一時的な値を使用しない場合、オプティマイザはそのストアを削除します。
それらはVBでも同じかもしれません。それらはC(演算子の由来)で必ずしも同じではありません。
Xがintやfloatのような単純な型である場合、オプティマイザーはおそらく同じ結果を生成します。
他の言語を使用する場合(ここでは限られたVB知識、+ =?をオーバーロードできますか?)、xは1つの大きなホーンオブジェクトになる可能性があり、前者は追加のコピーを作成し、数百になる可能性があります後者はそうではありません。
同じだ。
x=x+1
数学的に矛盾が見られますが、
x+=1
そうではなく、入力するのは軽いです。
C++では、データ型がxであり、演算子がどのように定義されているかによって異なります。 xがクラスのインスタンスである場合、まったく異なる結果を得ることができます。
または、質問を修正して、xが整数などであることを指定する必要があります。
違いはメモリ参照に使用される追加のクロックサイクルによるものだと思いましたが、間違っていることがわかりました。自分では理解できない
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それは役に立つかもしれないほんの一部のデータです。コメントしてください!
注目に値するのは、+ =、-=、* =などが暗黙的なキャストを行うことです。
int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.
Xが単純な整数スカラー変数の場合、それらは同じである必要があります。
Xが大きな式であり、おそらく副作用がある場合、+=1
および++
は2倍の速さである必要があります。
多くの人は、あたかもそれが最適化のすべてであるかのように、この種の低レベルの最適化に集中します。私はあなたがそれがはるかに大きな主題であることを知っていると思います。
実行時には(少なくともPerlでは)違いはありません。 x + = 1は、x = x +1よりも入力が約0.5秒速くなります。
プログラムの効率に違いはありません。タイピングの効率だけ。
1980年代初頭、Lattice Cコンパイラの非常に優れた最適化の1つは、「x = x + 1;」、「x + = 1;」でした。および「x ++;」すべてがまったく同じマシンコードを生成しました。彼らがそれを行うことができれば、この千年紀で書かれたコンパイラは間違いなくそれを行うことができるはずです。