[질문] 배열과 for문의 index에 따른 계산 속도

sinovercos의 이미지

안녕하세요.

일반적으로 n개의 원소를 갖는 배열을 선언하면, 0~(n-1)의 index를 사용합니다. 그리고 for(i=0;i<n;i++)와 같이 제어를 합니다.
저의 경우, 배열을 좌표와 대응시키려고 하는데, 배열의 index에 음수를 사용하면 코딩이 좀 더 편리해집니다.
음수 index는 malloc을 통해서 메모리를 할당할 때 적당한 수만 더해 주면, 사용할 수 있습니다.
문제는 계산 속도입니다. 제 코드는 한 계의 for문 안에 수십개의 배열 원소의 연산을 하도록 되어있습니다.
그래서, 같은 크기(n=10)의 배열과 연산들 이지만,

(1) for(i=0;i<10;i++) 연산(array[0~9)])
(2) for(i=-5;i<5;i++) 연산(array[-5~4])

와 같은 두 코드 사이에 계산 속도차가 있는지 알고 싶습니다.
compile하면 둘 다 동일하게 되면 좋겠지만, 그렇지 않을 수도 있을 것 같습니다.
혹시 알고 있으면 알려주시기 바랍니다.

서지훈의 이미지

제가 알기론 minus(-) 연산시 오버헤드가 더 걸리는 걸로 알고 있습니다.
아무래도 일반 수가 아니다보니 minus에 대한 처리까지 해 주어야 할기 때문이 아닌가 생각을 합니다.
그러나 요즘엔 워낙에 시스템들이 좋아져서 그렇게 차이는 나지 않을걸로 생각을 합니다.
아주 타이밍에 크리티컬한 경우가 아니라면 둘을 별로 구분할 필요까진 없을거 같군요.
10번 도는것 정도야 정말 눈 깜짝을 새니깐요...

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

yamainu의 이미지

아래와 같은 코드로 테스트를 해보았습니다.

A: for(i=200000000;i>0;i--)
B: for(i=0;i<200000000;i++)
C: for(i=-200000000;i<0;i++)
D: for(i=0;i>-200000000;i--)

결과는 다음과 같습니다.
A:
[yamainu@server c]$ time ./a.out

real    0m2.382s
user    0m2.110s
sys     0m0.000s
[yamainu@server c]$ time ./a.out

real    0m2.219s
user    0m2.070s
sys     0m0.000s
[yamainu@server c]$ time ./a.out

real    0m2.232s
user    0m2.070s
sys     0m0.010s
[yamainu@server c]$ time ./a.out

real    0m2.863s
user    0m2.090s
sys     0m0.000s
[yamainu@server c]$ time ./a.out

real    0m2.296s
user    0m2.090s
sys     0m0.000s

B:
[yamainu@server c]$ time ./a.out

real    0m2.019s
user    0m1.980s
sys     0m0.020s
[yamainu@server c]$ time ./a.out

real    0m2.018s
user    0m2.010s
sys     0m0.010s
[yamainu@server c]$ time ./a.out

real    0m2.021s
user    0m1.990s
sys     0m0.000s
[yamainu@server c]$ time ./a.out

real    0m2.175s
user    0m2.000s
sys     0m0.020s

[yamainu@server c]$ time ./a.out

real    0m2.358s
user    0m2.030s
sys     0m0.010s

C:
[yamainu@server c]$ time ./a.out

real    0m2.117s
user    0m2.080s
sys     0m0.010s
[yamainu@server c]$ time ./a.out

real    0m2.115s
user    0m2.110s
sys     0m0.000s
[yamainu@server c]$ time ./a.out

real    0m2.110s
user    0m2.090s
sys     0m0.010s
[yamainu@server c]$ time ./a.out

real    0m2.115s
user    0m2.060s
sys     0m0.020s
[yamainu@server c]$ time ./a.out

real    0m2.359s
user    0m2.050s
sys     0m0.010s

D:
[yamainu@server c]$ time ./a.out

real    0m2.018s
user    0m1.980s
sys     0m0.010s
[yamainu@server c]$ time ./a.out

real    0m2.015s
user    0m1.990s
sys     0m0.000s
[yamainu@server c]$ time ./a.out

real    0m2.057s
user    0m2.010s
sys     0m0.000s
[yamainu@server c]$ time ./a.out

real    0m2.007s
user    0m1.980s
sys     0m0.010s
[yamainu@server c]$ time ./a.out

real    0m2.018s
user    0m2.000s
sys     0m0.000s

음...결론적으로... ?

Programmers never die: They just GOSUB without RETURN.

서지훈의 이미지

이정도로는 별 결론을 내리기 힘들듯...-_-ㅋ
테스트 환경(4개의 프로그램이 돌 때의 cpu 정유율, memory 점유율)이 일정한지도 확인을 해봐야 할듯한데...-_-ㅋ
위 자료만으로는 별 차이가 없다고 보는게 맞겠죠...

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

kihlle의 이미지

- 두 경우는 동일합니다.

gcc -S 로 생성된 어셈블리코드라든가(같은 인스트럭션을 만들어냅니다)
별도의 프로파일러를 돌려보시면 아시겠지만, 두 경우 성능의 차이는 없습니다.

- 참고로, 덧셈과 뺄셈 연산도 같습니다.

증가연산(dec)와 감소연산(inc)의 성능은 같으며,
덧셈(adc,add)과 뺄셈(sbb,sub)의 성능도 같습니다.
(스펙상으로 386에서 reg,mem 형식은 덧셈이, mem,reg 형식은 뺄셈이 좀더 빠릅니다만 그차이도 무시해도 될겁니다.)
x86이 아닌 다른 CPU더라도 비슷할 것입니다.

마이너스처리로 오버헤드가 걸리는것은 인간의 두뇌 정도가 아닐까 싶습니다. :)

homeless

liongo의 이미지

흐흠 for문과 while도 얘기가 나오고

하는데 솔직히 호기심 거리가 될수 있지만

별로 요즘 콤퓨타성능을 봤을때

반복문의 속도는 거의 무의미하지 않나용..

솔직히 미세한 속도 튜닝을 위하려면 객체지향을

버려야하니까용..~ 그런거 같아서용.

지나가다 잡설이었습니당. -_-

돌날아오겟군..

' 형식이 내용을 규정한다. '

ssehoony의 이미지

음.. for(xxxx) 문 의 xxx 부분의 연산에 대한 포퍼먼스는 별로 의미가 없습니다.
거의 차이가 없어요.
왜냐구요? 덧셈, 뺼셈은 매우 빠르자나요
배열의 사용할때 문제는 곱셈이라고 할 수 있져.

가령

int i;
int num[100];

for( i = 0; i < 100; ++i)
{
	printf("%d\n", num[i]);
}

이런 코드가 있을 때
num[i] 에서는 내부적으로
(int*)((int)num + (i * sizeof(int)))
와 같은 계산이 일어납니다.

부분분을

int i;
int num[100];
int* p_num = num;

for( i = 0; i < 100; ++i)
{
	printf("%d\n", p_num);
	++p_num;
}

이렇게 고치면 계속 덧셈만 생기고 곱셈이 사라지져.
만약 for 문 안에 num[i] 를 접근하는 회수가 100번이면 100번 덧셈과 곱셈이 일어나는 셈이지만 p_num 을 별도로 만들어 사용하면 단 한번의 덧셈만 발생합니다.
그래서 loop 회수가 큰 부분에서는 배열을 저런식으로 접근하는게 좋지요.

참고로 위에 이야기가 있어서 말씀드리는데요
for(i = 0; i < 100; i++)
보다는
for(i = 0; i <100; ++i)
가 빠릅니다. (사실 거의 차이없지만 어셈차원에서 보면 ++i 가 빠르져)

그리고
for(i = 0; i < 100; ++i)
보다는
for(i = 100; i > 0; --i)
가 빠릅니다.
왜내구요? 시퓨는 i < 100 이라는 비교 연산보다 i > 0 이라는 0하고의 비교 연산이 빠릅니다. (이것도 어셈차원에서 0과의 비교 인스트럭션이 빨라서 그렇져)

for(i = 100; i > 0; --i)
이걸 사용해서 얻는 속력은 너무 미미하고 읽어버린 가독성은 큰편이라
비추천 입니다.

하지만 ++i 는 i++ 에 비해 가독성이 떨어지지 않으니 사용 권장이져 ^^

deisys의 이미지

for ( i = 0; i < 100; i++) ...
for ( i = 0; i < 100; ++i) ...

두개 모두 똑같은 어셈 코드를 만들어내는데요?? ( gcc 에서 -S 만 붙였습니다 )
어떤 경우에 속도차가 발생하지요...? 궁금하네요.
-O 도 추가해봤는데 두개가 별로 달라보이지 않네요.

Add.. 앗, 그리고 printf( .. , *p_num); 이 맞지 않나요?

cdpark의 이미지

i++와 ++i는 C 언어에선 전혀 다를 게 없습니다.

C++에서 ++ 연산자가 overloading된 경우엔 ++i 쪽이 더 효율적이지만요.

lunarainbow의 이미지

음. 제가 컴구조를 공부하며 알게된 사실은...

덧셈 연산과, 뺄셈 연산은 수행 속도에 차이가 없다~ 로 알고 있습니다.

덧셈의 operation code(OP code)가 00 이고,

뺄셈의 OP code가 01 이라고 가정했을때,

덧셈과 뺄셈의 수행 차이는, ALU operation (용어가 이거 맞던가?)에 1이 들어가고 안들어가고 차이입니다.

이때 들어가는 1은 2의 보수로 변환할때 마지막에 더해지는 1이며, 이것이 들어감에 따라 덧셈이냐 뺄셈이냐가 결정된다는..;;

좀 횡설수설한 감이 있는데... 결론적으로 말해서, 덧셈과 뺄샘은 OP code상의 차이일 뿐이지, 그것은 클럭에 영향을 미칠 수 없다. 입니다.

뭐.. 제가 보기엔 반복문 사용시에 가장 중요한 것은, 그것의 계산량이 O(n)이냐.. O(logn) 이냐.. O(n^2) 등등... 이런것이 중요할듯..

예전에 테스트해봤을때.. (아주 간단한 정렬의 효율 테스트)

환경은, 셀333, 리눅스 였습니다.

O(n^2) 알고리즘은 자그마치 3일 가량 걸렸습니다. :?

반면에 O(nlogn) 알고리즘은 단 몇초!!

물론 테스트셋은 동일했고, 기타 다른 시간은 모두 제외시킨, 순수하게 정렬 부분만 체크한 것이었습니다.

아마 이때 이 결과를 보고(이 전까지는 알고리즘이란, 단순히 어떤 문제를 해결하는 방법인줄로만 알고 있었습니다.)난 후부터, 알고리즘의 매력에 빠져든것 같습니다.

최소한의 자원으로 최대한 시간을 단축시킨다~ 라는..

덕분에 허구헌날 알고리즘만 생각해 보느라 다른거는 다 꽝이 되더군요. :wink:
(이건 말이 좀 안되는 얘긴가?)

ps. 역시 나의 횡설수설이란 ...

ixevexi의 이미지

i++와 ++i는 C++에서 차이가 있습니다.

임시객체가 생성되냐 안되냐의 차이죠 ^_^

i++는 그 값을 나타내기위한 임시객체가 필요하죠

즉 j = i++; 라고 할때 j에 대입되어야할 임시객체가 필요합니다.

하지만 ++i는
j = ++i;라고 할때 그저 i자신이 하나커지고 그냥 자신이 가서 대입합니다.
위에서 볼때 임시객체를 하나 생성하고 소멸시키는 시간에 비해 빠르단 거죠

C++, 그리고 C++....
죽어도 C++

wooix의 이미지

쉽게 생각하시면 됩니다.

-는 연산시 2' complement를 이용하지만 결국은 +와 마찬가지로 한 cycle내에 처리가 되도록 되어있습니다.

다중 cycle을 사용하지 않기때문에 성능의 차이를 기대하기는 어려울거 같습니다.

평온하다~

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.