手动编写循环的效率与运算符重载

时间:2010-04-22 05:46:44

标签: c++ performance operator-overloading numerical-computing

在我正在研究的程序中,我有3个元素的数组,我将它用作所有意图和目的的数学向量。

通过编写我的代码的过程,我很想用简单的算术重载(Vector)滚动我自己的+, -, * /类,所以我可以简化如下的语句:

// old:
for (int i = 0; i < 3; i++)
    r[i] = r1[i] - r2[i];

// new:
r = r1 - r2;

在生成的代码中应该或多或少相同。但是当谈到更复杂的事情时,这真的会严重影响我的表现吗?我在代码中的一个例子是:

手写版本:

for (int j = 0; j < 3; j++)
{
    p.vel[j] = p.oldVel[j] + (p.oldAcc[j] + p.acc[j]) * dt2 + (p.oldJerk[j] - p.jerk[j]) * dt12;
    p.pos[j] = p.oldPos[j] + (p.oldVel[j] + p.vel[j]) * dt2 + (p.oldAcc[j] - p.acc[j]) * dt12;
}

Vector类与运算符重载一起使用:

p.vel = p.oldVel + (p.oldAcc + p.acc) * dt2 + (p.oldJerk - p.jerk) * dt12;
p.pos = p.oldPos + (p.oldVel + p.vel) * dt2 + (p.oldAcc - p.acc) * dt12;

我正在尝试优化代码以提高速度,因为这种代码在内部循环中运行。使用重载运算符会影响性能吗?我正在对一个相互引力的物体系统进行数值积分。这些矢量操作非常常见,因此快速运行非常重要。

任何见解都会受到赞赏,就像我不知道的任何习语或技巧一样。

3 个答案:

答案 0 :(得分:2)

如果您的编译器内联并优化了操作,您通常不会发现编写代码(使用运算符使其可读和可维护)与手动内联所有内容之间存在任何差异。

手动内联也会大大增加错误的风险,因为您不会重复使用一段经过良好测试的代码,您将一遍又一遍地编写相同的代码。我建议用运算符编写代码,然后 if 你可以证明你可以通过手动内联,复制代码并手动内联第二个版本来加快速度。然后,您可以相互运行代码的两个变体,以证明(a)手动内联是有效的,以及(b)可读和手动内联代码都产生相同的结果。

在开始手动内联之前,您可以轻松地自己回答问题:从两个方面编写几个简单的测试用例,然后执行几百万次迭代,看看哪种方法执行得更快。这将教你很多关于正在发生的事情,并为你的特定实现和编译器提供一个明确的答案,你永远不会从你在这里得到的理论答案中得到答案。

答案 1 :(得分:2)

我想以相反的方式看待它;从Vector类开始,如果遇到性能问题,可以看看手动内联计算是否更快。

除了表现之外,您还提到计算必须准确。在类中进行向量特定计算意味着更容易单独测试它们,并且使用类的代码变得更短且更易于维护。

答案 2 :(得分:1)

查看ConCRT代码示例

http://code.msdn.microsoft.com/concrtextras/Release/ProjectReleases.aspx?ReleaseId=4270

有一对(包括一个NBody样本)使用Vector类型和模板等做了一堆这样的技巧。