重复计算的性能

Performance of duplicate computations

本文关键字:性能 计算      更新时间:2023-10-16

我想知道一次计算一次并存储结果或进行两次计算的速度是否值得?

例如,在这种情况下:

float n1 = a - b;
float n2 = a + b;
float result = n1 * n2 / (n1 * n2);

做最好的事情:

float result = (a - b) * (a + b) / ((a - b) * (a + b));

?我知道通常我们存储结果,但我想知道进行添加的速度不是更快,而不是调用内存存储/检索值。

这确实取决于:对于像您这样的琐碎示例,没关系。编译器将生成相同的代码,因为它找到了常见的子表达并消除了重复的计算。

对于更复杂的示例,例如涉及功能调用,最好使用第一个变体来"存储"中间结果。不用担心将简单变量用于中间存储。这些通常都保存在CPU寄存器中,并且编译器在保持寄存器中的价值方面相当不错。

危险在于,随着更复杂的计算,编译器可能无法进行常见的亚表达消除。例如,当您的代码包含函数调用时,这种情况像编译器边界一样。

另一个主题是,对于浮点,即使是添加的简单操作也不是关联的,即(a b) c与a (b c)不同,因为最低位中的伪影。由于不允许编译器更改代码的语义。

将表达式分为较小的表达式并给它们明智的名字给您一些好处:

  • 它减少了认知负荷。
  • 较长的表达现在可以更容易理解和验证正确。
  • 代码线可能短,使阅读并遵守编码标准变得更容易。

在C 中也可以标记临时变量const,然后允许编译器更好地优化表达式。

但是,在讨论并将其用作参数之前,应测量优化。快速通常来自数据结构和使用算法的选择。

在一般代码中应写入理解和正确,然后才能优化。


const float difference = a - b;
const float sum        = a + b;
const float result     = difference * sum / (difference * sum);