gpt4 book ai didi

c++ - 提高一个非常简单但经常使用的函数的效率(计算晶格中原子的邻居)

转载 作者:行者123 更新时间:2023-11-28 00:42:15 25 4
gpt4 key购买 nike

我在这里相对较新,但我认为如果有人可以提供帮助,这里会有人。

我们正在做一个非常大规模的原子晶格模拟程序,这个非常简单的函数被使用了太多次,以至于它大大减慢了这个过程。

它只是检查周期性晶格中一个位点的 8 个邻居(我们在 BCC 中)的类型(称为晶格的 3d 结构 vector 的一部分,包括表示原子类型的整数 t)。

我意识到可能无法进一步简化它,但如果有人有任何灵感请告诉我,谢谢!

//calculates number of neighbours that aren't vacancies
int neighbour(int i, int j, int k)
{
//cout << "neighbour" << endl;
int n = 0;

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++;
}
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++;
}

return n;
}

最佳答案

首先,仅当 LATTICE_SIZE 是 2 的幂时,使用的格子环绕解决方案 ((i+1) & (LATTICE_SIZE-1)) 才能正常工作。例如,如果 LATTICE_SIZE == 100i == 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 );

我的测量显示每次调用 neighbor() 大约需要 12 纳秒。之后我注意到邻居只在两个高阶平面上被检查。我重构了函数以向优化器提供更明确的提示:

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 纳秒。我检查了编译器的输出,发现这次它已将两个函数内联到调用循环中并生成了一个数字对我的优化。均衡器它有效地将两个内部循环移动到 neighbour_in_plane() 函数中,从而避免了数千次重新计算格子[(i-+1) & (LATTICE_SIZE-1)] 表达式。

最重要的是,您必须在您的代码+编译器+平台环境中使用此功能才能最大限度地利用它。

关于c++ - 提高一个非常简单但经常使用的函数的效率(计算晶格中原子的邻居),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18201869/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com