首先,使用中的格子环绕解决方案 ( (i+1) & (LATTICE_SIZE-1)
) 仅当 LATTICE_SIZE 是 2 的幂时才能正常工作。例如,如果LATTICE_SIZE == 100
和i == 99
,
(i+1)&(LATTICE_SIZE-1) == 100 & 99 == 0x64 & 0x63 == 0x60 == 96
,而预期值为 0。
鉴于此,我建议您检查多维数组索引在您的编译器和平台上的工作方式。当 LATTICE_SIZE 等于 2 的幂时,第 n 个索引的乘法可以有效地用左移代替,这在某些架构上明显更快。VC++11 会自动进行这种优化,但是我不知道你的编译器是什么,也不能假设它也这样做。
想到的另一个改进是尽量避免从高阶索引重新计算偏移量。如果我们将相同的高阶索引组合在一起,优化器可以帮助实现这一目标。我只是通过对表达式进行排序来实现这一点:
if (V != lattice[(i+1) & (LATTICE_SIZE-1)][(j+1) & (LATTICE_SIZE-1)][k ].t) n++;
if (V != lattice[(i+1) & (LATTICE_SIZE-1)][j ][k+1].t) n++;
if (V != lattice[(i+1) & (LATTICE_SIZE-1)][j ][k-1].t) n++;
if (V != lattice[(i+1) & (LATTICE_SIZE-1)][(j-1) & (LATTICE_SIZE-1)][k ].t) n++;
if (V != lattice[(i-1) & (LATTICE_SIZE-1)][(j+1) & (LATTICE_SIZE-1)][k ].t) n++;
if (V != lattice[(i-1) & (LATTICE_SIZE-1)][j ][k+1].t) n++;
if (V != lattice[(i-1) & (LATTICE_SIZE-1)][j ][k-1].t) n++;
if (V != lattice[(i-1) & (LATTICE_SIZE-1)][(j-1) & (LATTICE_SIZE-1)][k ].t) n++;
我的优化器利用了这一点,结果加速只有 4%。但是,对于您的系统,它可能会归结为不同的值。
此外,大部分优化实际上取决于函数的使用。例如,我写了一个这样的简单测试:
volatile int n = 0;
for ( int i = 0; i != LATTICE_SIZE; ++i )
for ( int j = 0; j != LATTICE_SIZE; ++j )
for ( int k = 0; k != LATTICE_SIZE; ++k )
n += neighbour ( i, j, k );
我的测量显示每个 neighbour() 调用大约 12 ns。之后我注意到邻居只在两个高阶飞机上检查。我重构了函数以向优化器提供更明确的提示:
int neighbour_in_plane ( elem_t l[LATTICE_SIZE][LATTICE_SIZE], int j, int k )
{
int n = 0;
if (V != l[(j-1) & (LATTICE_SIZE-1)][k ].t) n++;
if (V != l[j ][k-1].t) n++;
if (V != l[j ][k+1].t) n++;
if (V != l[(j+1) & (LATTICE_SIZE-1)][k ].t) n++;
return n;
}
//calculates number of neighbours that aren't vacancies
int neighbour(int i, int j, int k)
{
return neighbour_in_plane ( lattice[(i-1) & (LATTICE_SIZE-1)], i, j ) +
neighbour_in_plane ( lattice[(i+1) & (LATTICE_SIZE-1)], i, j );
}
令人惊讶的是,每次调用只有 4 ns。我检查了编译器输出,发现这一次它已将两个函数内联到调用循环中,并为我做了一些优化。Eq 它有效地将两个内部循环移动到 neighbour_in_plane() 函数中,从而避免了数千次重新计算
lattice[(i-+1) & (LATTICE_SIZE-1)]
表达式。
底线是你必须在你的代码+编译器+平台环境中使用这个函数才能最大限度地利用它。