source

x=x+1 대x + = 1

manycodes 2023. 5. 21. 11:40
반응형

x=x+1 대x + = 1

저는 이 두 명령이 같은 결과, 즉 X를 1씩 증가시키지만 후자가 아마도 더 효율적일 것이라고 생각합니다.

만약 이것이 정확하지 않다면, diff를 설명해주세요.

만약 그것이 맞다면, 왜 후자가 더 효율적이어야 합니까?둘 다 같은 IL로 컴파일해야 하지 않나요?

감사해요.

MSDN 라이브러리에서 +=:

이 연산자를 사용하는 것은 결과가 한 번만 평가된다는 점을 제외하고는 결과 = 결과 + 식을 지정하는 것과 거의 같습니다.

따라서 이들은 동일하지 않으므로 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);
}

그들은 같습니다.

그들은 동일하게 컴파일하고, 두 번째는 타이핑하기가 더 쉽습니다.

중요:

한 답은 정확합니다.+=도, 일반적인 언어로.에서는 VB를 하만지라고 합니다.NET에서는, 제가 봤을 때는.XOP에 지정된 것은 변수 또는 속성입니다.


그들은 아마 같은 IL로 컴파일될 것입니다.

업데이트(아마도 발생할 수 있는 논란 해결):

언어의 입니다.VB.NET은 프로그래밍 언어입니다.사양에 정의된 내용을 준수하는 컴파일러는 VB.NET 구현이 될 수 있습니다.하여 MS VB에 대한 를 생성하는 .NET 컴파일러의 소스 코드를 편집하여 다음에 대한 크래피 코드를 생성하는 경우X += 1예를 들어, VB.NET 사양을 여전히 준수할 것입니다(VB.NET 사양에는 작동 방식에 대한 설명이 없었기 때문입니다).그것은 단지 효과가 정확히 같을 것이라고 말하고, 이것은 실제로 동일한 코드를 생성하는 것을 논리적으로 만듭니다.)

컴파일러가 두 가지 모두에 대해 동일한 코드를 생성할 가능성이 매우 높지만(나는 실제로 그렇게 생각합니다) 꽤 복잡한 소프트웨어입니다.이런, 당신은 컴파일러가 같은 코드를 두 번 컴파일할 때 정확히 같은 코드를 생성한다는 보장조차 할 수 없습니다!

컴파일러의 소스 코드를 자세히 알지 못하는 한 100% 안전하다고 느낄 수 있는 것은 훌륭한 컴파일러가 성능 면에서 동일한 코드를 생성해야 한다는 것입니다. 이는 정확히 동일한 코드일 수도 있고 아닐 수도 있습니다.

정말 많은 추측들!심지어 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에서도 마찬가지야.그물

x86에서 x가 레지스터 eax에 있으면 둘 다 다음과 같은 결과를 초래합니다.


그래서 당신 말이 맞아요, 편집 단계가 끝나면 IL도 똑같을 거예요.

이와 같은 질문에는 "최적화 도구를 신뢰하라"는 질문이 있습니다.

유명한 신화는
x++;
보다 효율성이 떨어집니다.
++x;
임시 값을 저장해야 하기 때문입니다.임시 값을 사용하지 않으면 최적화 도구가 해당 저장소를 제거합니다.

  1. 네, 그들은 똑같이 행동합니다.
  2. 아니요, 그들은 아마도 똑같이 효율적일 것입니다.옵티마이저는 그런 것에 능합니다.더블 체크를 원하시면 최적화된 코드를 작성하여 리플렉터에서 확인하시기 바랍니다.

x가 int 또는 float와 같은 단순한 유형인 경우 최적화 도구는 동일한 결과를 생성할 수 있습니다.

만약 당신이 다른 언어(여기서 제한된 VB 지식, +=?)를 사용한다면, 여기서 x는 하나의 큰 경적 객체일 수 있고, 전자는 수백 메그가 될 수 있는 여분의 복사본을 만들 수 있습니다.후자는 그렇지 않습니다.

똑같습니다.

x=x+1 

수학적인 것은 모순으로 보이는 반면에.

x+=1

그렇지도 않고 가볍게 입력할 수 있습니다.

VB에서는 동일할 수 있지만 C(측정 시스템의 출처)에서는 동일할 필요가 없습니다.

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://sshot_sshot.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

모두 동일한 것으로 나타났습니다. 도움이 될 수 있는 몇 가지 데이터만 있습니다.댓글 달아주세요!

주의할 점은 +=, -=, *= 등이 암시적 캐스트를 한다는 것입니다.

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

실행 시간(최소한 PERL 사용 시)에는 차이가 없습니다.x+=1은 x=x+1보다 입력 속도가 약 0.5초 빠릅니다.

프로그래밍 효율성에는 차이가 없고 타이핑 효율성만 있습니다.

1980년대 초, Lattice C 컴파일러의 정말 멋진 최적화 중 하나는 "x = x + 1;", "x + = 1;", "x + + +;" 모두 정확히 동일한 기계 코드를 생성했다는 것입니다.만약 그들이 그것을 할 수 있다면, 이 밀레니엄으로 작성된 컴파일러는 분명히 그것을 할 수 있을 것입니다.

x가 단순 정수 스칼라 변수인 경우에는 동일해야 합니다.

만약 x가 큰 표현식이라면, 부작용이 있을 수 있습니다.+=1그리고.++두 배 더 빨라야 합니다.

많은 사람들이 이런 종류의 낮은 수준의 최적화에 집중합니다. 마치 그것이 최적화의 전부인 것처럼 말입니다.훨씬 더 큰 주제라는 것을 알고 계실 겁니다.

언급URL : https://stackoverflow.com/questions/808062/x-x1-vs-x-1

반응형