C/C++에서 integer변수 swap 방법 비교
- 박동식 (검색포털본부 신규검색엔진개발팀)
C++에서 integer변수의 swap을 할때 어떤 방법이 가장 빠른지 문득 궁금증이 들어서 테스트해보았습니다.
서론 #
- 변수를 바꿔치기 하는데 일반적으로 사용하는 방법인 std::swap, xor를 이용한 swap macro, tmp변수를 이용한 swap방법 세가지의 속도를 비교해보았습니다.
std::swap #
- std::swap : c++에서 일반적으로 가장 널리쓰이는 안전한 방법
#include <iostream>
#include <algorithm>
#include<stdio.h>
int main(void)
{
int a = 1;
int b = 2;
for(int i=0;i<50000000;i++)
{
std::swap(a,b);
}
return printf("%d %d",a, b);
}
결과
$ time ./swap.out 1 2 real 0m0.560s user 0m0.557s sys 0m0.003s
-O2옵션을 붙혀 테스트한 결과
$ time ./a.out 1 2 real 0m0.048s user 0m0.047s sys 0m0.001s
xor를 이용한 방법 #
- c에서 예전에 많이 사용되던 방법 임시변수를 사용하지 않아서 좋다는 장점이 있음.
- 오래된 CPU에서는 이 방법이 빨랐으나 최근 CPU에서는 bit operation이 느려서 그다지 좋지 않다고 알려져있습니다.
#include <iostream>
#include <algorithm>
#include<stdio.h>
#define SWAP(a,b) { if (a!=b) { a^=b; b^=a; a^=b; }}
int main(void)
{
int a = 1;
int b = 2;
for(int i=0;i<50000000;i++)
{
SWAP(a,b);
}
return printf("%d %d",a, b);
}
결과
$ time ./xor.out 1 2 real 0m0.504s user 0m0.502s sys 0m0.003s-O2옵션을 붙혀 테스트한 결과
$ time ./a.out 1 2 real 0m0.071s user 0m0.070s sys 0m0.001s
임시변수를 이용한 방법 #
- 가장 기본적인 방법. 임시변수를 사용한다는 단점이 있습니다.
#include <iostream>
#include <algorithm>
#include<stdio.h>
#define SWAP(a,b) { int t=a; a=b; b=t; }
int main(void)
{
int a = 1;
int b = 2;
for(int i=0;i<50000000;i++)
{
SWAP(a,b);
}
return printf("%d %d",a, b);
}
결과
$ time ./a.out 1 2 real 0m0.274s user 0m0.272s sys 0m0.002s-O2옵션을 붙혀 테스트한 결과
$ time ./a.out 1 2 real 0m0.048s user 0m0.046s sys 0m0.002s
-O2를 붙였을 경우 std::swap과 임시변수는 성능이 거의 같았음.
결론 #
- 최근의 cpu환경에서 integer를 swap하는경우 그냥 임시변수를 선언하여 swap하는게 빠르다는 결론을 얻을 수 있었습니다.
- 단순히 룹을 돌며 테스트한거라 실제 프로그램 수행중엔 조금 다르게 동작할 수 있을것으로 생각됩니다.
- integer에 한정된 테스트결과임으로 다른 타입인경우 달라질 수 있습니다.
- 옵티마이즈 옵션을 켜고 돌려보았습니다. std::swap과 SWAP매크로의 성능이 거의 비슷한것을 확인할 수 있었습니다.
std::swap
.L6:
movl %edi, %edx // edi:a edx:tmp a->tmp
decl %eax // loop counter
movl %ecx, %esi // ??
movl %ecx, %edi // ecx:b edi:a b->a
movl %edx, %ecx // edx:tmp ecx:b tmp->b
jns .L6
swap macro
.L5:
movl %ecx, %esi // ecx:a esi:tmp a->tmp
decl %eax // loop counter
movl %edx, %ecx // edx:b ecx:a b->a
movl %esi, %edx // esi:tmp edx:b tmp->b
jns .L5
std:swap에서는 %esi레지스터 값을 업데이트 하는데 function call을 옵티마이즈 하면서 남은 더미가 아닐까 싶습니다.
g++이 아닌 다른 컴파일러에서 옵티마이징을 할 경우 다른 결과가 나올 수 있을것으로 생각합니다.