我有一个C程序,可以对大型数组进行大量的交换操作。它在紧密的循环中有一个模运算。事实上,[-N | N [N
范围内的整数是2的幂,它应该被包装为[0,N [。
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
对于可以使用它的两种情况来说实际上更快。
答案 0 :(得分:0)
首先take a few stackshots找出实际上的时间。您的mod
函数会抓取一部分样本,但您还有两次调用random
,加上相当数量的数组索引。此外,看起来您已经有四次调用en
且一些参数相同,因此您的模块化可能导致重复调用mod
函数。