我有一個C程序,它在大型陣列上做了一些廣泛的交換操作。它在緊密的循環中有模操作。實際上,範圍[-N | N [有N
的整數範圍是2的冪,它應該被換成[0,N [。Modulo優化
實施例與N = 4:-4 => 0,-3 => 1,-2 => 2,-1 => 3,0 => 0,...,3 => 3
起初,我嘗試了下面的版本1,但感到驚訝的是即使它有一個條件表達式,版本2實際上也顯着更快。
你能解釋爲什麼版本2比版本1更快爲這種特殊情況?
版本1:
#define N (1<<(3*5))
inline int modBitAnd(int x)
{
return (x & (N-1));
}
運行時間:17.1秒(對於整個程序)
版本2:
inline int modNeg1(int x)
{
return (x < 0 ? x + N : x);
}
運行時間:14.6秒(對於整個程序)
程序在GCC 4.8.2上編譯。與-std = c99 -O3。
編輯:
這裏是我在程序的主循環:
int en(uint16_t* p, uint16_t i, uint16_t v)
{
uint16_t n1 = p[modNeg1((int)i - 1)];
uint16_t n2 = p[modBitAnd((int)i + 1)];
uint16_t n3 = p[modNeg1((int)i - C_WIDTH)];
uint16_t n4 = p[modBitAnd((int)i + C_WIDTH)];
return d(n1,v) + d(n2,v) + d(n3,v) + d(n4,v);
}
void arrange(uint16_t* p)
{
for(size_t i=0; i<10000000; i++) {
uint16_t ia = random(); // random integer [0|2^15[
uint16_t va = p[ia];
uint16_t ib = random(); // random integer [0|2^15[
uint16_t vb = p[ib];
if(en(p,ia,vb) + en(p,ib,va) < en(p,ia,va) + en(p,ib,vb)) {
p[ia] = vb;
p[ib] = va;
}
}
}
int d(uint16_t a, uint16_t b)
是距離函數例如abs((int)a-(int)b)
。
這是p
如何初始化:
uint16_t* p = malloc(sizeof(uint16_t)*N);
for(unsigned i=0; i<N; i++) *p++ = i;
首先,我用modBitAnd
無處不在,但發現該modNeg1
是實際上可以更快的爲兩種情況下可以使用。
您是否嘗試過查看編譯器生成的彙編代碼? – Medinoc
第二個版本不能正常工作,除非你傳給它一個餘數結果,因爲它沒有模數發生 –
哪個平臺(32或64位)?此外,請[發佈完整的代碼示例](http://meta.stackoverflow.com/a/258849/509868)或反彙編列表。 – anatolyg