- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在这里相对较新,但我认为如果有人可以提供帮助,这里会有人。
我们正在做一个非常大规模的原子晶格模拟程序,这个非常简单的函数被使用了太多次,以至于它大大减慢了这个过程。
它只是检查周期性晶格中一个位点的 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 == 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 );
我的测量显示每次调用 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/
我可能使用了错误的术语,但正在寻求帮助。 我想为位于椭圆形状周边的网格生成 x,y 值数组。 这里有代码:http://people.sc.fsu.edu/~jburkardt/c_src/ellip
我是一名优秀的程序员,十分优秀!