循环变量条件的C循环优化

Ben*_*Ben 10 c optimization loops

如果在档案中询问,请道歉.我发现了一些类似的问题,但没有一个看起来正是我想要的.

我正在研究的问题的提炼版本如下.我有一系列要执行的计算,它们将值存储在4个(非常大的)数组中:A,B,C和D.这些计算是相互依赖的,例如计算b [i]可能需要使用[i-1].我能够在一个循环中表达所有内容,但这导致边缘情况,对于某些i值,只应执行一些计算.例如:

for(i=0;i<end;i++)
{
    if(i == 0)
        //calculate A[i+1] and B[i+1]
    else if (i == end-1)
        //calculate C[i-1] and D[i-1]
    else
        //calculate A[i+1], B[i+1], C[i-1], D[i-1]
}
Run Code Online (Sandbox Code Playgroud)

对于性能问题,我想避免在我的循环中有条件.与计算相比,评估条件是便宜的,但可能不可忽略.我的问题是编译器是否可以可靠地将其扩展为

//calculate A[1] and B[1]
for(i=1;i<end-1;i++)
{
    //calculate A[i+1], B[i+1], C[i-1], D[i-1]
}
//calculate C[end-2] and D[end-2]
Run Code Online (Sandbox Code Playgroud)

我从档案中收集到,如果条件表达式是常量的,编译器会分裂我的循环,但是这里它们依赖于i,原则上我可以通过一些计算来改变它.它是否会检测到我没有篡改迭代变量,从而以合理的方式将其分开?

如果您决定通过建议更好的方式来回答问题,请提供额外信息:

最初代码是用4个循环编写的,用于计算每个数组的元素.这是编写代码最直观的方法,但效率很低.由于计算一个数组中的元素取决于其他数组中的元素,这意味着我必须在4个循环中的每个循环中从内存中读取所有4个数组.由于这些数组不适合缓存,这不是最佳的,我需要的代码只能在我的数组中循环一次.

我也知道我可以手动分开我的循环,事实上这就是目前的事情.然而,这些计算涉及非平凡的公式(并且我无法承受在此循环的每次迭代期间调用函数的性能损失),因此分解代码导致代码重复,这不仅非常难以阅读,而且几乎无法维护下一个我的公式得到调整的时间(他们将......)

提前致谢!

Ada*_*iss 3

从更广泛的意义上回答您的问题:当优化至关重要时,分析器就是您的朋友。众所周知,开发人员不善于猜测处理器在代码中的哪个位置花费了大部分时间。分析器将准确地向您显示“昂贵”操作的位置,以便您可以集中精力修复将为您带来最显着改进的区域。

我很好奇你的说法,即你“无法承受在这个循环的每次迭代期间调用函数的性能损失......”你是怎么知道的?许多现代处理器都针对函数调用进行了优化,特别是如果您可以传递指针(指向struct?)而不是许多单独的参数。如果您的计算确实“不平凡”,那么函数调用的开销可能可以忽略不计。

其他需要考虑的事情:

  • 作为实验,重新索引您的计算,以便它们尽可能精确地i自行运行,而不是i-1或。i+1因此,例如,使用A[i]B[i]C[i-2]D[i-2]。如果使用优化编译器取得显着改进,我会感到惊讶,但你永远不知道......

  • 预先计算任何可以做的事情。

  • 正如 James Greenhalgh 所建议的那样,尝试将计算分解为较小的恒定或常见组件,以便它们可以被重用。

  • 你能更有效地重写你的方程吗?数学分析可能会引导您找到一条捷径:也许您可以以封闭形式重写部分(或全部)迭代。

  • 你能用更简单的东西完全代替你的方程吗?例如,假设您需要根据距您家的距离对一组位置进行排序。距离计算需要减法、平方、加法和平方根。一般来说,平方根是迄今为止最昂贵的运算。但如果您只需要相对距离,则可以完全跳过平方根:按距离的平方排序会生成相同的排序顺序!

  • 如果内联不可能,您能否将函数(或其组件)定义为高效的宏,这样至少可以避免重复代码?正如您所提到的,剪贴板继承是可维护性的死敌。

如果不出意外的话,通过这个练习将教会您大量关于编译器和 C 语言工作方式的知识。祝你好运!