32

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

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

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

ありがとう。

4

17 に答える 17

109

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

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

したがって、それらは同一ではないため、 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 
}
于 2009-04-30T17:25:52.400 に答える
26

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

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

それらは同じです。

于 2009-04-30T17:29:29.990 に答える
18

それらは同じにコンパイルされます.2番目は入力が簡単です.

于 2009-04-30T17:17:58.613 に答える
11

重要:

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


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

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

VB.NET は、プログラミング言語の仕様です。仕様で定義されているものに準拠するコンパイラはすべて、VB.NET 実装にすることができます。MS VB.NET コンパイラのソース コードを編集して、大文字と小文字を区別してくだらないコードを生成するX += 1場合でも、VB.NET 仕様に準拠することになります (これは、VB.NET 仕様がどのように機能するかについて何も述べていないためです。まったく同じになるため、同じコードを生成することが論理的になります)。

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

100% 安心して言えることは (コンパイラのソース コードをよく知っている場合を除きます)、優れたコンパイラはパフォーマンスに関して同じコードを生成する必要があるということです

于 2009-04-30T17:17:32.467 に答える
8

非常に多くの憶測!Reflector に関する結論でさえ、逆アセンブル中に最適化を行うことができるため、必ずしも真実ではありません。

では、なぜ誰も 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でも同じです

于 2009-04-30T18:03:13.323 に答える
4

x86 では、x がレジスタ eax にある場合、どちらも次のような結果になります。

inc eax;

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

「オプティマイザを信頼してください」と答えることができる、このような種類の質問があります。

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

于 2009-04-30T17:24:25.837 に答える
2

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

于 2009-04-30T17:18:27.333 に答える
2
  1. はい、同じように動作します。
  2. いいえ、おそらく同等に効率的です。オプティマイザーはそのようなことを得意としています。再確認したい場合は、最適化されたコードを記述し、リフレクターで表示します。
于 2009-04-30T17:18:40.420 に答える
2

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

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

于 2009-04-30T17:19:08.330 に答える
2

同じだ。

x=x+1 

は数学的に矛盾していると見なされますが、

x+=1

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

于 2009-04-30T17:20:51.197 に答える
1

+=、-=、*= などは暗黙のキャストを行うことに注意してください。

int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.
于 2009-05-01T06:38:34.897 に答える
1

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

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

于 2009-04-30T18:56:18.767 に答える
1

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

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 役立つデータがいくつかあります。コメントしてください!

于 2009-04-30T18:57:00.247 に答える
0

x が単純な整数スカラー変数の場合、それらは同じでなければなりません。

x が大きな式の場合、副作用がある可能性があり、+=12++倍の速度になるはずです。

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

于 2009-05-01T11:51:46.767 に答える
0

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

于 2009-04-30T17:18:18.893 に答える
0

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

于 2009-04-30T17:20:24.660 に答える
0

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

于 2009-04-30T17:24:43.853 に答える