我有一个处理多个嵌套循环的程序,在3D域上运行:
unsigned int sX(m_sizeZ*m_sizeY);
unsigned int b(sX+m_sizeZ);
for(unsigned int i(1);i<m_sizeX-1;i++){
for(unsigned int j(1);j<m_sizeY-1;j++){
for(unsigned int k(1);k<m_sizeZ-1;k++){
m_r[b+k]=m_func[b+k]-m_cX*(m_data[b+k-sX]+m_data[b+k+sX]-2.0*m_data[b+k])
-m_cY*(m_data[b+k-m_sizeZ]+m_data[b+k+m_sizeZ]-2.0*m_data[b+k])
-m_cZ*(m_data[b+k-1]+m_data[b+k+1]-2.0*m_data[b+k]);
}
b+=m_sizeZ;
}
b+=2*m_sizeZ;
}
我的数组大小为m_sizeX * m_sizeY * m_sizeZ。
的两倍我以这种方式迭代,因为我不想触及域的边界。
使用(g ++)-msse2 -ftree-vectorizer-verbose = 2进行编译时,我当然会得到多个嵌套循环注释。
有没有办法在没有(或多或少)复杂的检查操作的情况下使用单个循环?
谢谢!
答案 0 :(得分:2)
如果您的目标是良好的矢量化,最好将相同的计算应用于边缘点和内部点,只有在计算完所有点后重置它们。像这样:
unsigned int sX(m_sizeZ*m_sizeY);
unsigned int start = (1*m_sizeY + 1)*m_sizeZ + 1;
unsigned int end = ((m_sizeX - 1)*m_sizeY - 1)*m_sizeZ - 1;
//Do calculation for everything, including the edges.
for(unsigned int i = start; i < end; i++) {
m_r[i]=m_func[i]-m_cX*(m_data[i-sX]+m_data[i+sX]-2.0*m_data[i])
-m_cY*(m_data[i-m_sizeZ]+m_data[i+m_sizeZ]-2.0*m_data[i])
-m_cZ*(m_data[i-1]+m_data[i+1]-2.0*m_data[i]);
}
//Reset the edges.
for(unsigned x = 0; x < m_sizeX; x++) {
for(unsigned y = 0; y < m_sizeY; y++) {
m_r[x*sX + y*m_sizeZ] = m_data[x*sX + y*m_sizeZ];
m_r[x*sX + y*m_sizeZ + m_sizeZ-1] = m_data[x*sX + y*m_sizeZ + m_sizeZ-1];
}
}
for(unsigned x = 0; x < m_sizeX; x++) {
for(unsigned z = 0; z < m_sizeZ; z++) {
m_r[x*sX + z] = m_data[x*sX + z];
m_r[x*sX + (m_sizeY-1)*m_sizeZ + z] = m_data[x*sX + (m_sizeY-1)*m_sizeZ + z];
}
}
这是可以进行的额外计算,但它有两个积极的影响:
现在编译器很容易对第一个循环进行矢量化(大部分时间都是这样)。
这种方法几乎消除了由固定向量大小引起的边缘问题:由于向量单元在一个处理多个对齐(!)循环迭代,计算中的每个边缘都会导致需要进行两次特殊迭代完成。一个在运行开始时将矢量循环对齐,另一个在末尾处理矢量循环的剩余部分。
答案 1 :(得分:1)
您可以在一个循环中从1
到m_sizeX*m_sizeY*m_sizeZ
(使用计数器C
)进行迭代并计算i
,j
,{{1 as:
k
此方法的约束条件是您必须处理i = C / (m_sizeY*m_sizeZ)
j = (C % (m_sizeY*m_sizeZ)) / m_sizeZ
k = (C % (m_sizeY*m_sizeZ)) % m_sizeZ
范围内的m_sizeX*m_sizeY*m_sizeZ
而不会溢出。
修改强>
要在不使用C
子句的情况下控制边界,您可以创建一个函数
if-else
并在循环中使用它:
size_t nextToCalculate(size_t previous)
{
return previous+1+!condition;
}
甚至可以将其实施纳入其中:
for(int C = 0; C < m_sizeX*m_sizeY*m_sizeZ; C = nextToCalculate(C))
{
int z = (C % (m_sizeY*m_sizeZ)) % m_sizeZ;
int y = (C % (m_sizeY*m_sizeZ)) / m_sizeZ;
int x = C / (m_sizeY*m_sizeZ);
...
...
...
}
答案 2 :(得分:0)
将代码作为可编译的整个函数。初看:
答案 3 :(得分:0)
你可以试试这个(单圈,如你所要求的):
unsigned int sX(m_sizeZ*m_sizeY);
unsigned int b(sX+m_sizeZ);
unsigned int i, j, k;
for (i = 1, j = 1, k = 1;
i < m_sizeX-1 && j < m_sizeY - 1 && k < m_sizeZ - 1;
k++) {
m_r[b+k]=m_func[b+k]-m_cX*(m_data[b+k-sX]+m_data[b+k+sX]-2.0*m_data[b+k])
-m_cY*(m_data[b+k-m_sizeZ]+m_data[b+k+m_sizeZ]-2.0*m_data[b+k])
-m_cZ*(m_data[b+k-1]+m_data[b+k+1]-2.0*m_data[b+k]);
if (k == (m_sizeZ - 2)) {
if (j == (m_sizeY - 2)) {
b+=2*m_sizeZ;
j = 0;
i++;
}
k = 0;
b+=m_sizeZ;
j++;
}
}