我又发了一篇文章
here在那里我问如何在三维空间中创建一个立方体素节点的26个邻居。我得到了一个非常好的答案并实施了它。
为此,我添加了一些MIN MAX位置检查。
我想知道是否有方法,与3 for循环相关,4如果使用,以改善此代码的执行时间。我在另一篇文章中读过,当使用while循环时速度更快但是它的帖子不是语言特定的。
这是真的吗?如果是的话,请你在我的代码中帮助我,因为我有运气经历吗? 有没有办法以一种能让它更快的方式递归地实现它?
这是我的代码:
...
std::vector<Pos> Create26Neighbor(Pos somePos, double resol)
{
std::vector <Pos> vect1;
Pos m_MinPos(0.0,0.0,0.0);
Pos m_MaxPos(5.0,4.0,5.0);
for (double dz = somePos.m_pPos[2] - resol; dz <= somePos.m_pPos[2] + resol; dz+=resol)
{
if (dz>m_MinPos.m_pPos[2] && dz<m_MaxPos.m_pPos[2])
{
for (double dy = someCPos.m_pPos[1] - resol; dy <= someCPos.m_pPos[1] + resol; dy+=resol)
{
if (dy>m_MinPos.m_pPos[1] && dy<m_MaxPos.m_pPos[1])
{
for (double dx = somePos.m_pPos[0] - resol; dx <= somePos.m_pPos[0] + resol; dx+=resol)
{
if (dx>m_MinPos.m_pPos[0] && dx<m_MaxPos.m_pPos[0])
{
// all 27
if ((dx != somePos.m_pPos[0]) || (dy != somePos.m_pPos[1]) || (dz != somePos.m_pPos[2]))
{
Pos tempPos(dx,dy,dz);
vect1.push_back(tempPos);
}
}
}
}
}
}
}
return vect1;
}
....
答案 0 :(得分:5)
首先,摆脱if语句。没有必要。您可以将它们合并到循环条件中。其次,避免每次迭代重新计算循环条件。是的,编译器可能会对其进行优化,但它通常对浮点优化非常保守(并且它可能会将从内存中读取的fp值与从寄存器中读取的值不同,这意味着它不能从循环条件中消除数组查找),因此通常最好手动进行简单的优化:
std::vector<Pos> Create26Neighbor(Pos somePos, double resol)
{
std::vector <Pos> vect1(27); // Initialize the vector with the correct size.
Pos m_MinPos(0.0,0.0,0.0);
Pos m_MaxPos(5.0,4.0,5.0);
double minz = std::max(somePos.m_pPos[2] - resol, m_MinPos.m_pPos[2]);
double maxz = std::min(somePos.m_pPos[2] + resol, m_MaxPos.m_pPos[2];
int i = 0;
for (double dz = min; dz <= max; dz+=resol)
{
double miny = std::max(somePos.m_pPos[1] - resol, m_MinPos.m_pPos[1]);
double maxy = std::min(somePos.m_pPos[1] + resol, m_MaxPos.m_pPos[1];
for (double dy = miny; dy <= maxy; dy+=resol)
{
double minx = std::max(somePos.m_pPos[0] - resol, m_MinPos.m_pPos[0]);
double maxx = std::min(somePos.m_pPos[0] + resol, m_MaxPos.m_pPos[0];
for (double dx = minx; dx <= maxx; dx+=resol)
{
++i;
// If we're not at the center, just use 'i' as index. Otherwise use i+1
int idx = (dx != somePos.m_pPos[0] || dy != somePos.m_pPos[1] || dz != somePos.m_pPos[2]) ? i : i+1;
vec1[idx] = Pos(dx, dy, dz); // Construct Pos on the spot, *might* save you a copy, compared to initilizing it, storing it as a local variable, and then copying it into the vector.
}
}
}
return vect1;
}
我考虑的最后一点是内部的if语句。紧密循环中的分支可能比您预期的更昂贵。我可以想出一些消除它的方法:
确保编译器展开内部循环。手动展开它也可能有所帮助。
最后,很大程度上取决于Pos的定义方式。
请注意,我建议的大部分内容都符合“它可能不会更快,但......”。您必须不断地对每个变更进行分析和基准测试,以确保您实际上提高了性能。
根据您愿意走多远,您可以将所有内容合并为一个循环(在整数上运行),并在每次迭代中动态计算Pos坐标。
答案 1 :(得分:3)
如果没有像域名过滤这样的“智能”,你可能不会找到很多简化立方方程的方法。
真的,我在这里发帖的真正原因是代码坦白地说是 beasty ,即:eugh。呸。我有一个个人的,最近开发的对嵌套代码的讨厌,并会努力将一些内部循环导出到一个单独的函数, DESPITE 它将添加的额外理论开销(简介它,小函数通常会内联)
我个人的观点是,如果你的代码具有高性能,但没有人能够理解它,那么它比次优但可维护的代码更糟糕。
此外,如果您可以保证相对于起点固定坐标的数量,您可以通过对结构进行硬编码来获益,也就是说,手动执行,即:
function generate26( x,y,z ){
return [
# Top
# Left
[x-1,y+1,z-1],
[x-1,y+1,z],
[x-1,y+1,z+1]
];
}
或者生成一个宏或2来为你做。
至少在某种程度上,你完全依赖编译器优化内存结构的能力,没有循环或任何东西。 (虽然可以确定它的概况)
答案 2 :(得分:2)
从语言的角度来看,您可以通过在向量中保留26(或27,具体取决于您的数字:) :)项目来提高性能:
std::vector<Pos> vect1;
vect1.reserve(27);
这将使内部数组足够大并避免重新分配向量。
返回向量,或通过引用传递向量并写入更高性能只会通过测试来计算。编译器可以优化返回值副本。
一般情况下,如果您优化算法本身(或通过选择另一个算法),您将获得更多性能提升,而不是尝试优化其实现。
答案 3 :(得分:2)
有没有办法实现这一点 以一种可以实现的方式递归地递归 快?
没有。真的,没有。
递归意味着函数调用,通常是大量的。函数调用意味着堆栈操作和(可能)上下文更改,这些操作相对较慢。
递归是一个功能强大的工具,可用于执行一些非常棘手的事情,同时保持可读性,但它不是一种高性能技术。在最好的情况下,您可能会发现一个编译器可以优化尾递归,以便像普通循环一样快速运行 - 这可以通过将递归代码转换为幕后的正常循环来实现。
答案 4 :(得分:1)
所有for循环基本上都采用以下形式:
for (d_ = somPos._ - resol; d_ <= somPos_.+resol; d_+= resol)
这恰好执行了3次。如果用表格中的东西替换这三个for循环,这段代码可能会更快:
double dz = somePos.m_pPos[2] - resol;
for(z = 0; z < 3; z++, dz += resol)
在这里使用common for循环表单将允许优化器根据需要展开这些循环。我不认为你的另一种形式很简单,优化者可以发现它真的只会发生3次。这个是。
编辑:此外,如果您使用const或#define作为MinPos / MaxPos值,编译器可能会加速我们 little 位。我不认为它能够像你拥有它们那样确定值是非常常量的。
答案 5 :(得分:1)
比较与浮点数的相等性是非常危险的,容易出错。
按值传递和返回对象?根据您的对象,这可能会减慢速度。
就优化而言,尽可能在最“外”循环中测试变量。但实际上,您似乎比循环优化有更大的问题需要担心。
答案 6 :(得分:1)
所以基本上,在正常情况下,你想要向量添加26个位置,这些可以很容易枚举,除了你必须小心不要访问超出的体素边界。
如果您确实想要将此功能优化到最大值,那么最佳实现将是单个开关和展开循环。
对于3个维度中的每个维度,只有五个可能性:
case 1: {somePos[i] - resol}; // 1 value only
case 2: {somePos[i] - resol, somePos[i]} // 2 values
case 3: {somePos[i] - resol, somePos[i], somePos[i] + resol} // all 3
case 4: {somePos[i], somePos[i] + resol} // 2 values again
case 5: {somePos[i] + resol} // 1 value only
还有一个“case 0”,其中 none 的值在范围内。但是,如果对于任何维度都是如此,则根本不添加任何值。
为三个维度中的每个维度组合5个可能性,为您提供125个可能的实施案例。根据您获得的125个案例中的哪一个,您可以将循环和ifs展开为最多26个push_back()调用的序列。
这样的事情:
enum eCase {
CASE_NONE = 0,
CASE_LOW1 = 1,
CASE_LOW2 = 2,
CASE_ALL3 = 3,
CASE_HIGH2 = 4,
CASE_HIGH1 = 5,
};
eCase Xcase = /* a function of somePos[0], m_MinPos[0], m_MaxPos[0], and resol */
eCase Ycase = ...
eCase Zcase = ...
#define MUNGE(_x,_y,_z) (((((_x)*6)+(_y))*6)+(_z))
switch (MUNGE(Xcase, Ycase, Zcase) {
default:
break; // all CASE_NONE's do nothing
case MUNGE (CASE_ALL3, CASE_ALL3, CASE_ALL3):
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] - resol, somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] - resol, somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] - resol, somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] , somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] , somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] , somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] + resol, somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] + resol, somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] - resol, somePos.m_pPos[1] + resol, somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] - resol, somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] - resol, somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] - resol, somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] , somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] , somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] + resol, somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] + resol, somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] , somePos.m_pPos[1] + resol, somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] - resol, somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] - resol, somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] - resol, somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] , somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] , somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] , somePos.m_pPos[2] + resol));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] + resol, somePos.m_pPos[2] - resol));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] + resol, somePos.m_pPos[2] ));
vect1.push_back( pos (somePos.m_pPos[0] + resol, somePos.m_pPos[1] + resol, somePos.m_pPos[2] + resol));
break;
......还有124个案例要去!
不要 - 重复不要 实际上手工编写所有这些代码! 没有编码难以找到的bug,任何人都无法做到这一点。 写另一个程序来代替编写源代码。 : - )
答案 7 :(得分:1)
std::vector<Pos> Create26Neighbor(Pos somePos, double resol)
{
std::vector<Pos> vect1(26);
Pos m_MinPos(0.0,0.0,0.0);
Pos m_MaxPos(5.0,4.0,5.0);
double z = somePos.m_pPos[2] - resol;
for(int dz = -1; dz <= 1; ++dz) {
z += resol;
if(z <= m_MinPos.m_pPos[2] || z >= m_MaxPos.m_pPos[2])
continue;
double y = somePos.m_pPos[1] - resol;
for(int dy = -1; dy <= 1; ++dy) {
y += resol;
if(y <= m_MinPos.m_pPos[1] || y >= m_MaxPos.m_pPos[1])
continue;
double x = somePos.m_pPos[0] - resol;
for(int dx = -1; dx <= 1; ++dx) {
x += resol;
if(dx == 0 && dy == 0 && dz == 0)
continue;
if(x <= m_MinPos.m_pPos[0] || x >= m_MaxPos.m_pPos[0])
continue;
vect1.push_back(Pos(x, y, z));
}
}
}
return vect1;
}
我尝试对此进行优化以提高可读性。你真的关心速度吗?我不认为速度对于创建一些邻居节点非常重要。您是否已分析过您的代码以确定这是否是瓶颈?
答案 8 :(得分:0)
我没有试图弄明白,但你可以用SSE2 / Altivec /其他矢量指令做一些漂亮的事情,一次做多个比较。