我需要迭代一个摊销公式,如下所示:
R = ( L * (r / m) ) / ( 1 - pow( (1 + (r / m)), (-1 * m * t ) );
我正在使用for
循环进行迭代,并且每次将L(贷款值)递增1。循环工作正常,但它确实让我想知道其他东西,这是在循环执行之前执行基本操作然后通过变量引用这些值的值(或缺少它)。例如,我可以进一步修改此函数,使其看起来像
// outside for loop
amortization = (r/m)/(1 - pow( (1+(r/m)), (-1*m*t) ) )
// inside for loop
R = L * amortization
这样,我不必在循环的每次迭代中执行大量的数学运算,而只需引用变量并执行单个操作。
我想知道这是多么相关?在提取这些操作时是否有任何实际价值,或节省的时间如此之小以至于我们所说的是从迭代约为的for循环中节省了几毫秒。 200,000次。跟进问题:如果我做sqrt
等更昂贵的操作,那么提取这样的操作是否值得?
(注意:如果重要的话,我会特别考虑c ++的问题)
答案 0 :(得分:2)
编译器会在这里运用一种称为循环不变代码运动的优化技术。它几乎完成了你手动完成的工作,即将循环中反复评估的表达式的常量部分提取到存储在变量(或寄存器)中的预先计算的值中。因此,您自己不可能获得任何表现。
当然,如果速度很关键,那么在两种情况下都应该分析和/或查看编译器生成的汇编代码。
答案 1 :(得分:2)
编译器已将循环不变代码移动到循环外部。此优化称为“Loop Invariant Code Motion”或“吊装不变量”。
如果你想知道它对性能有多大影响,那么你要知道的唯一方法就是尝试。我想如果你这样做了200,000次,那肯定会影响性能(如果编译器还没有为你做这个)。
答案 2 :(得分:2)
正如其他人所提到的,好的编译器会自动进行这种优化。然而...
首先,pow
可能是库函数,因此您的编译器可能知道也可能不知道它是一个“纯”函数(即,它的行为仅取决于它的参数)。如果没有,它将无法执行此优化,因为它知道pow
可能会打印一条消息或其他内容。
其次,我认为将这个表达式从循环中分解出来会使代码更容易理解。读取代码的人也可以“自动”分解出这个表达式,但为什么要这样做呢?它只是分散了你的算法流程。
所以无论如何我都会说这个改变。
那就是说,如果你真的关心性能,那就得到一个不错的分析器,不要担心微观优化,直到它告诉你。你早期的优先事项应该是(a)使用一个不错的算法和(b)清楚地实现它。而不是那个顺序。
答案 3 :(得分:1)
如果你打开了opimizations,那么在循环之外移动常量表达式是编译器非常擅长自己做的事情,所以这可能会让你无法加速。
但如果不这样做,那么尝试是合理的,然后计时,如果这实际上花费的时间超过了你的要求。