预先计算的变量是否比在循环中每次计算它更快?

时间:2014-12-26 10:16:19

标签: c++ performance c++11

在更新所有粒子的函数中,我有以下代码:

for (int i = 0; i < _maxParticles; i++)
{
    // check if active
    if (_particles[i].lifeTime > 0.0f)
    {
        _particles[i].lifeTime -= _decayRate * deltaTime;
    }
}

这会根据经过的时间减少粒子的寿命。 它会在每个循环中计算出来,所以如果我有10000个粒子,那么它不会非常高效,因为它不需要(它不会被改变)。

所以我想出了这个:

float lifeMin = _decayRate * deltaTime;

for (int i = 0; i < _maxParticles; i++)
{
    // check if active
    if (_particles[i].lifeTime > 0.0f)
    {
        _particles[i].lifeTime -= lifeMin;
    }
}

这计算一次并将其设置为每个循环调用的变量,因此CPU不必每次循环计算它,理论上会提高性能。

它会比旧代码运行得更快吗?或者发布编译器是否进行了这样的优化?

我写了一个比较两种方法的程序:

#include <time.h>
#include <iostream>

const unsigned int MAX = 1000000000;

int main()
{
    float deltaTime = 20;
    float decayRate = 200;

    float foo = 2041.234f;

    unsigned int start = clock();

    for (unsigned int i = 0; i < MAX; i++)
    {
        foo -= decayRate * deltaTime;
    }

    std::cout << "Method 1 took " << clock() - start << "ms\n";

    start = clock();

    float calced = decayRate * deltaTime;

    for (unsigned int i = 0; i < MAX; i++)
    {
        foo -= calced;
    }

    std::cout << "Method 2 took " << clock() - start << "ms\n";

    int n;
    std::cin >> n;
    return 0;
}

调试模式的结果:

Method 1 took 2470ms
Method 2 took 2410ms

结果处于发布模式:

Method 1 took 0ms
Method 2 took 0ms

但这并不奏效。我知道它并没有完全相同,但它提出了一个想法。 在调试模式下,它们大致需要相同的时间。有时方法1比方法2更快(特别是数量更少),有时方法2更快。 在释放模式下,需要0 ms。有点奇怪。

我尝试在游戏中测量它,但是没有足够的粒子来获得清晰的结果。

修改 我尝试禁用优化,并使用std::cin让变量成为用户输入。 结果如下:

Method 1 took 2430ms
Method 2 took 2410ms

2 个答案:

答案 0 :(得分:4)

这几乎肯定会产生什么不同,至少如果有的话 你用优化编译(当然,如果你关心的话) 性能,你正在编译优化)。最优化的 问题被称为循环不变代码运动,并且是普遍的 实施(并已经实施了大约40年)。

另一方面,可能有意义使用单独的变量 无论如何,要使代码更清晰。这取决于应用程序,但是 在许多情况下,给表达式的结果命名可以 代码更清晰。 (在其他情况下,当然,投入了很多额外的 变量可以使它不那么清晰。这一切都取决于应用程序。) 在任何情况下,对于这样的事情,尽可能清楚地编写代码 首先,然后,如果(并且仅当)存在性能问题, 个人资料,看看它在哪里,并修复它。

编辑:

非常清楚:我一般都在讨论这种代码优化。在您显示的确切情况下,由于您不使用foo,编译器可能会完全删除它(和循环)。

答案 1 :(得分:1)

理论上,是的。但是你的循环非常简单,因此需要进行大量优化。

尝试使用-O0选项禁用所有编译器优化。

发布运行时可能是由编译器静态计算结果引起的。

我非常有信心,任何体面的编译器都会用以下代码替换你的循环:

foo -= MAX * decayRate * deltaTime;

foo -= MAX * calced ;

您可以根据某种输入(例如命令行参数)设置MAX大小以避免这种情况。