10

我想了想:这两种做法是否存在性能差异:

  1. 将函数的返回值存储在临时变量中,而不是将该变量作为参数提供给另一个函数。
  2. 将函数放入另一个函数中。

规格

假设所有类和函数都正确编写。

情况1。

ClassA a = function1();
ClassB b = function2(a);
function3(b);

案例 2。

function3(function2(function1()));

我知道只运行一次没有太大区别,但假设我们可以在一个循环中运行很多次,我创建了一些测试。

测试

#include <iostream>
#include <ctime>
#include <math.h>
using namespace std;

int main()
{
   clock_t start = clock();
   clock_t ends = clock();

   // Case 1.
   start = clock();
   for (int i=0; i<10000000; i++)
   {
      double a = cos(1);
      double b = pow(a, 2);
      sqrt(b);
   }
   ends = clock();
   cout << (double) (ends - start) / CLOCKS_PER_SEC << endl;

   // Case 2.
   start = clock();
   for (int i=0; i<10000000; i++)
      sqrt(pow(cos(1),2));
   ends = clock();
   cout << (double) (ends - start) / CLOCKS_PER_SEC << endl;
   return 0;
}

结果

  • 案例 1 = 6.375
  • 案例 2 = 0.031

为什么第一个慢得多,如果第二个更快,为什么我们不总是那样写代码?无论如何,第二个练习有名字吗?
我还想知道如果我在第一种情况下在 for 循环之外创建变量会发生什么,但结果是一样的。为什么?

4

2 回答 2

4

如果您想要计算紧缩并且您的数字变得更加一致,请打破所有这些优化。为了确保获得正确值的代码实际运行并且没有完全丢弃,我已经将两个测试中的结果分配给了一个 volatile 本地(这不是 volatile 的正确使用,但在确保只有价值创造是显着的增量)。

#include <iostream>
#include <ctime>
#include <cmath>
using namespace std;

int main()
{
    clock_t start;
    volatile double val;

    for (int j=1;j<=10;j++)
    {
        // Case 1.
        start = clock();
        for (int i=0; i<2000000; i++)
        {
            double a = cos(1);
            double b = pow(a, 2);
            val = sqrt(b);
        }
        cout << j << ':' << (double) (clock() - start) / CLOCKS_PER_SEC << endl;

        // Case 2.
        start = clock();
        for (int i=0; i<2000000; i++)
            val = sqrt(pow(cos(1),2));
        cout << j << ':' << (double) (clock() - start) / CLOCKS_PER_SEC << endl << endl;
    }
    return 0;
}

在我的 Macbook Air 上生成以下发布编译的输出(无论如何都不是速度恶魔):

1:0.001465
1:0.001305

2:0.001292
2:0.001424

3:0.001297
3:0.001351

4:0.001366
4:0.001342

5:0.001196
5:0.001376

6:0.001341
6:0.001303

7:0.001396
7:0.001422

8:0.001429
8:0.001427

9:0.001408
9:0.001398

10:0.001317
10:0.001353
于 2012-12-19T17:08:38.200 回答
0

对上述两个循环进行适当且合法的全面优化是“甚至不执行循环”。您可能很容易看到在第一种情况下使用未初始化的变量混淆了编译器,或者您使用变量可能会混淆它,或者您的优化级别可能会强制命名变量实际存在。

现在在 C++11 中两者之间存在差异,涉及到临时变量的隐式移动,但您可以使用std::move. (我不确定,但最后一次使用超出范围的局部变量可能有资格进行隐式移动)。对于 adouble这没有区别,但对于更复杂的类型则可以。

于 2012-12-19T17:10:41.327 回答