全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2777
推到 Plurk!
推到 Facebook!

一個陣列初始化問題

 
shihyu
一般會員


發表:20
回覆:17
積分:7
註冊:2002-11-30

發送簡訊給我
#1 引用回覆 回覆 發表時間:2006-09-02 06:55:10 IP:59.104.xxx.xxx 訂閱

我看一些C的程式範例對陣列初始話

例如: 要把 a 陣列清成 0

int a[10000];

for ( i = 0; i < 10000; i )

a[i] = 0;

int a[10000] = {0};

這兩個作法哪個效率比較高????

謝謝

Stallion
版主


發表:52
回覆:1600
積分:1995
註冊:2004-09-15

發送簡訊給我
#2 引用回覆 回覆 發表時間:2006-09-02 13:29:08 IP:211.22.xxx.xxx 未訂閱
應該是第2個方法。
第2個初始化陣列的方法其內容在COMPILE TIME就決定了。
第1個陣列初始化的內容要在執行時期才決定。
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#3 引用回覆 回覆 發表時間:2006-09-02 19:30:25 IP:61.229.xxx.xxx 未訂閱

雖然結果都是 int a[ ] = {0} 的方式比較快,但原因不全然是因為在complie time 時決定的關係。
必需看a[ ] 是在哪裡定義/宣告的。同樣是用 {0} 初始化,但義意不同
若 a [ ]是外在變數(即在function外),那麼就是靜態的放在exe檔內,且早就初始化成0,run的時候根本就無需初始。
若 是內在變數(在function內),那它的值是在stack完成後開始才作初始化,與用for是一樣的道理。只是…
那二句statement所產生的機器碼是不一樣的。
用{0} 的方式,它的ASM大概是用
mov esi, xxxx;
lea edi, xxxxx;
mov ecx, xxxx;
rep movsd;
來跑,這幾個微指令用的時間很短
而for的話則用許多的微指令
而且還額外呼叫vcl裡的CG_LDA_EOXSY( )
慢很多。
我實測a[100000]的結果大概是
for 用了18,172,000 cycles
{0} 則用了 584,069 cycles
近30倍的差異

蕭沖 qs.xiao@gmail.com
http://aftcast.blogspot.com/

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2006-09-03 00:01:12 IP:61.229.xxx.xxx 未訂閱
抱歉,剛注意到我忘了把GodeGuard關起來,導致多呼叫了CG_LDA_EOXSY( )
把程式重跑一下…
我實測a[100000]的結果大概是
for 用了1,193,851
{0} 則用了 346,143 cycles
近3.4倍的差異

===================引 用 文 章===================

而for的話則用許多的微指令
而且還額外呼叫vcl裡的CG_LDA_EOXSY( )
慢很多。
我實測a[100000]的結果大概是
for 用了18,172,000 cycles
{0} 則用了 584,069 cycles
近30倍的差異

蕭沖 qs.xiao@gmail.com
http://aftcast.blogspot.com/

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
shihyu
一般會員


發表:20
回覆:17
積分:7
註冊:2002-11-30

發送簡訊給我
#5 引用回覆 回覆 發表時間:2006-09-03 02:29:24 IP:59.104.xxx.xxx 訂閱

===================引 用 文 章===================
抱歉,剛注意到我忘了把GodeGuard關起來,導致多呼叫了CG_LDA_EOXSY( )
把程式重跑一下…
我實測a[100000]的結果大概是
for 用了1,193,851
{0} 則用了 346,143 cycles
近3.4倍的差異

===================引 用 文 章===================

而for的話則用許多的微指令
而且還額外呼叫vcl裡的CG_LDA_EOXSY( )
慢很多。
我實測a[100000]的結果大概是
for 用了18,172,000 cycles
{0} 則用了 584,069 cycles
近30倍的差異

蕭沖 qs.xiao@gmail.com
http://aftcast.blogspot.com/

__________________________________________________________________________________

請問是用BCB 去測試效率嗎??? 可以教一下怎麼測試嗎??? 很想知道怎麼去做測試

謝謝

shihyu
一般會員


發表:20
回覆:17
積分:7
註冊:2002-11-30

發送簡訊給我
#6 引用回覆 回覆 發表時間:2006-09-05 15:43:59 IP:59.104.xxx.xxx 訂閱

===================引 用 文 章===================
抱歉,剛注意到我忘了把GodeGuard關起來,導致多呼叫了CG_LDA_EOXSY( )
把程式重跑一下…
我實測a[100000]的結果大概是
for 用了1,193,851
{0} 則用了 346,143 cycles
近3.4倍的差異

===================引 用 文 章===================

而for的話則用許多的微指令
而且還額外呼叫vcl裡的CG_LDA_EOXSY( )
慢很多。
我實測a[100000]的結果大概是
for 用了18,172,000 cycles
{0} 則用了 584,069 cycles
近30倍的差異

蕭沖 qs.xiao@gmail.com
http://aftcast.blogspot.com/
______________________________________________________________________

To aftcast

請問用bcb 測到的 cycles 是指需使用到的微指令行數嗎???

可以請問一下用 bcb 測試 cycles 要如何去使用它

謝謝


aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#7 引用回覆 回覆 發表時間:2006-09-06 00:41:55 IP:61.229.xxx.xxx 未訂閱


===================引 用 文 章===================
你好,

並非微指令行數,是cpu時脈下經過了多少次。所以每台測的結果會有些不同,因為時脈不同。
每個微指令都有它一定的cycle,不一定等於一,你假想微指令就像是function一樣,不同的function本身跑完所需的時間是不同的。以微指令MOV來說,一般是跑二個cycle,也就是說MOV ax, bx需要跑二次。至於二次要多久? 那就要看cpu的時脈了,了解了嗎?

測的方式是用自定的time-stamp counter function來實作的,所以不一定要在bcb裡,只要能使用inline assembly就可以。請參加我的程式: (for BCB)

__int64 GetCounter(void)
{
asm rdtsc //will put counter to EDX(high):EAX(low)
//convention return int64 will return eax to variable lower part
//and edx to higher part, so just matched with rdtsc naturally
}

在你想要測的片段statements的前面和後面取數,相減得差,就可以知道約經過多少個cycles。

PS. 這個function本身會得到一個warnning,說是沒有return值。這是沒關係的,因為rdtsc這個微指令執行完成後就會把counter計入EDX:EAX上,而我們這個function使用__int64為回傳值,剛好就是會return EDX:EAX ! 另外,不是所有的語言的inline asm都有support這個指令,所以在不同的語言上可能需要做調整,或是直接給opcode等…

===================引 用 文 章===================

To aftcast

請問用bcb 測到的 cycles 是指需使用到的微指令行數嗎???

可以請問一下用 bcb 測試 cycles 要如何去使用它

謝謝


------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
shihyu
一般會員


發表:20
回覆:17
積分:7
註冊:2002-11-30

發送簡訊給我
#8 引用回覆 回覆 發表時間:2006-09-06 07:26:55 IP:59.104.xxx.xxx 訂閱

//---------------------------------------------------------------------------

#include
#include
#pragma hdrstop

//---------------------------------------------------------------------------

__int64 GetCycleCount(void)
{
asm rdtsc
//will put counter to EDX(high):EAX(low)
//convention return int64 will return eax to variable lower part
//and edx to higher part, so just matched with rdtsc naturally
}


int main(int argc, char* argv[])
{
unsigned long t;
int a[10000],i;

t = (unsigned long)GetCycleCount();

for (i ; i <= 10000; i )
a[i] = 0;
t -= (unsigned long)GetCycleCount();

cout << t << endl;

system("pause");
return 0;
}
//---------------------------------------------------------------------------
上面這樣跑不出數據 , 是否我哪邊弄錯??

不過下面測試 int a[10000] = {0} ; 這樣可以跑出一組數據

t = (unsigned long)GetCycleCount();

int a[10000] = {0};

t -= (unsigned long)GetCycleCount();

謝謝

aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#9 引用回覆 回覆 發表時間:2006-09-06 18:22:16 IP:61.229.xxx.xxx 未訂閱

for (i ; i <= 10000; i ) <<---是不是因為 i 沒初始化的關係?

還有,最好是設定三個變數
unsigned long diff;
__int64 start, end;
start = GetCounter();
........
........
end = GetCounter();
diff = (unsigned long) (start - end);


保持簡單的敘述 start = ....,end = 會比較精準一些,還有因為那個回傳值最好用__int64來接,但因為一般的output io不太support int64,所以用 unsinged long 來做差值剛好,一方面夠,二方面可以輸出!
以上是我的建議… :-)

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#10 引用回覆 回覆 發表時間:2006-09-06 18:22:57 IP:61.229.xxx.xxx 未訂閱
剛打錯了,修正
diff = (unsigned long) (end - start);
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
shihyu
一般會員


發表:20
回覆:17
積分:7
註冊:2002-11-30

發送簡訊給我
#11 引用回覆 回覆 發表時間:2006-09-06 18:44:34 IP:210.64.xxx.xxx 訂閱


===================引 用 文 章===================
剛打錯了,修正
diff = (unsigned long) (end - start);

____________________________________________________________________

//---------------------------------------------------------------------------

#include
#include
#pragma hdrstop

//---------------------------------------------------------------------------

__int64 GetCounter(void)
{
asm rdtsc
//will put counter to EDX(high):EAX(low)
//convention return int64 will return eax to variable lower part
//and edx to higher part, so just matched with rdtsc naturally
}


int main(int argc, char* argv[])
{
unsigned long diff;
__int64 start, end;
int a[10000],i;


start = GetCounter();

for (i = 0 ; i <= 10000; i )
a[i] = 0;

end = GetCounter();

diff = (unsigned long) (end - start);
cout << diff << endl;

system("pause");
return 0;
}

我是在console 測試

這樣還是跑不出數據 =.=

aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#12 引用回覆 回覆 發表時間:2006-09-07 01:48:21 IP:61.229.xxx.xxx 未訂閱

剛把你的程式貼到我的project裡測式,發現…

for (i = 0 ; i < 10000; i )

你再試看看吧!
===================引 用 文 章===================


for (i = 0 ; i <= 10000; i )

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
shihyu
一般會員


發表:20
回覆:17
積分:7
註冊:2002-11-30

發送簡訊給我
#13 引用回覆 回覆 發表時間:2006-09-07 06:45:34 IP:59.104.xxx.xxx 訂閱

===================引 用 文 章===================

剛把你的程式貼到我的project裡測式,發現…

for (i = 0 ; i < 10000; i )

你再試看看吧!
===================引 用 文 章===================


for (i = 0 ; i <= 10000; i )

_______________________________________________________________________________

原來是出超範圍 @@ .... 抱歉我搞笑了 .... BCB 用 for Tab 後自動產生 (i = 0; i <= 10; i )

因為很不常使用BCB 所以沒有留意 <= 問題 =.=

謝謝

shihyu
一般會員


發表:20
回覆:17
積分:7
註冊:2002-11-30

發送簡訊給我
#14 引用回覆 回覆 發表時間:2006-09-07 09:17:19 IP:59.104.xxx.xxx 訂閱

請問 cycle 值是不是每次跑出來的值都不太一樣 , 這樣是正常嗎 ??cycle 每次跑數據都不 一樣是什麼原因??

我用 int a[10000] = {0} 的cycle 值 > 大於 for 的cycle 值 .... ><

還有一個怪問題 當我第ㄧ次跑 int a[10000] = {0} ; 是50幾萬 , 再讓它跑第一次下降到10幾萬 , 之後測試都是10幾萬

還是需要哪邊要設定之類的??

謝謝

aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#15 引用回覆 回覆 發表時間:2006-09-07 23:04:13 IP:61.229.xxx.xxx 未訂閱
最新研究報告出來了!!

1/ 每次不太一樣是正常的,因為這是多工的環境,但值應該都平均接近
2/ 根據我反組譯程式看,發現一個我沒想過的事…
若是用 [ ] = {0} 的方式,complier是會把整個陣列先當作外在變數一樣,把整個陣列放入程式exe檔內(以ASM來說,就是DATA區段內),於是即使在函式內宣告 a[10000] = {0}; 照常還是會造成exe檔變大! 可以試著把陣列變很大,你會看到exe檔變超大的 -_-||| 。當實際上跑的時候才又使用rep movsd微指令把.DATA區的資料copy到stack上…這與用for是不一樣的,當你在函式內宣告b[10000]是不會在.DATA區內有值,而是在實際上跑的時候,在Stack上劃出一塊來放,然後用for把值一個一個的設定到區塊。所以,就算b宣告超級大,檔案還是不會變! (如原本所知的情形)
3/ 但就 rep movsd 與 for 所用的微指令來比較,rep movsd的確是比較快。因為他只用了7 4n個cycles (n次),而for裡面的mov 就要2個cycle,但不只mov 一次,等等…所以 rep movsd一定比較快!
4/ 然而…為什麼第一次跑的數據爆大,然後才又變小?? 我推斷是因為windows paging的關係。事實上當程式在跑的時候,並不是整個exe全部load至記憶體,而是部份在RAM上,部份在disk上(swarp)。而當我們需某些資料的時候才立刻把swarp的資料載入RAM上,這種過程就是paging。因為windows 有cache的能力,同樣的程式被載入第二次一定會比第一次快(可以試著開word之類的,開了再關)。所以,應該是第一次的.DATA資料還在swarp中,值到處理至rep movsd時因為動到了DATA區的資料,所以才被載入RAM上,才開始一個一個的copy資料。這個載入的過程就花了不少的時間。而當第二次再跑程式的時候,DATA區的資料已在RAM上,就沒有載入的問題,於是就看出rep movsd真正的速度!
5/ 實驗: 可以把程式編好後copy(不能用rename)至另一個檔名,用新的檔案來跑,第一次又變慢,第二次又快。同樣的程式在copy至另一個新名字,也有同樣的情形。這就是windows cache的能力!
6/結論: 從上面的事實來看覺得內在變數還是乖乖的使用for來處理,因為A/執行檔不會變大B/若只會此function只被叫用一次,那就虧更大了C/for的方式與rep movsd 的方式僅差3倍左右,應該算還好。當然,若陣列值小的時候,比如說1000個 int值,那麼檔案多增4k左右,但速度變快,且沒有第一次,第二次的問題,因為整個區塊小,開始的時候可能就都被載入RAM中了。


===================引 用 文 章===================

請問 cycle 值是不是每次跑出來的值都不太一樣 , 這樣是正常嗎 ??cycle 每次跑數據都不 一樣是什麼原因??

我用 int a[10000] = {0} 的cycle 值 > 大於 for 的cycle 值 .... ><

還有一個怪問題 當我第ㄧ次跑 int a[10000] = {0} ; 是50幾萬 , 再讓它跑第一次下降到10幾萬 , 之後測試都是10幾萬

還是需要哪邊要設定之類的??

謝謝

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
系統時間:2024-05-13 10:14:29
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!