C ++这是一种微优化形式

时间:2013-04-29 16:46:12

标签: c++ micro-optimization

这是微观优化,还是优化呢?

void Renderer::SetCamera(FLOAT x, FLOAT y, FLOAT z) {
    // Checking for zero before doing addition?
    if (x != 0) camX += x;
    if (y != 0) camY += y;
    if (z != 0) camZ += z;

    // Checking if any of the three variables are not zero, and performing the code below.
    if (x != 0 | y != 0 | z != 0) {
        D3DXMatrixTranslation(&w, camX, camY, camZ);
    }
}

运行带有vector.size()的条件的for循环会强制应用程序重新计算每个循环中向量中的元素吗?

std::vector<UINT> vect;

INT vectorSize = vect.size();
for (INT Index = 0; Index < vectorSize; Index++) {
// Do vector processing
}

// versus:

std::vector<UINT> vect;

for (INT Index = 0; Index < vect.size(); Index++) {
// Do vector processing
}

我正在使用Visual Studio,而对于第二个问题,它似乎是编译器可以优化的东西,但我只是不确定。

4 个答案:

答案 0 :(得分:5)

根据向量的实现,编译器可能会或可能不会理解大小未更改。毕竟,你在循环中调用不同的向量函数,其中任何一个都可能改变大小。

因为vector是一个模板,所以编译器知道它的一切,所以如果它真的很难,它可以理解大小不会改变,但这可能太多了。

通常,你会想这样写:

for (size_t i = 0, size = vect.size(); i < size; ++i)
    ...

虽然我们正在使用它,但迭代器使用了类似的方法:

for (list<int>::iterator i = lst.begin(), end = lst.end(); i != end; ++i)
    ...

编辑:我错过了第一部分:

这是优化吗?

if (x != 0) camX += x;
if (y != 0) camY += y;
if (z != 0) camZ += z;

没有。首先,即使它们是int,也不是优化,因为检查和分支时值很可能是大多数时候不是零是更多的工作。

其次,更重要的是,它们是浮动的。这意味着除了you shouldn't directly compare them to 0之外,它们基本上几乎不会完全等于0.所以if s的真实度为99.9999%。

同样适用于此:

if (x != 0 | y != 0 | z != 0)

然而,在这种情况下,由于矩阵转换成本很高,您可以这样做:

#define EPS 1e-6 /* epsilon */
if (x > EPS || x < -EPS || y > EPS || y < -EPS || z > EPS || z < -EPS)

现在是的,与矩阵乘法相比,这可能是一种优化。

另请注意,我使用的||会被短路,例如从开头x > EPS开始就是真的(它不会计算其余部分),但|表示{{1}}不会发生。

答案 1 :(得分:2)

我怀疑在许多架构上前三行都是反优化,因为它们可能引入浮点比较然后分支,这可能比只是总是进行加法更慢(即使它是浮点数)。

另一方面,确保在进行转换之前至少有一个组件非零是正确的。

对于您的第二种情况,size必须是固定时间,并且几乎可以肯定地直接访问vector的大小。它很可能完全可以优化。也就是说,有时它可以通过保存大小来更容易地读取代码/循环,因为这清楚地表明你断言大小在循环期间不会改变。

答案 2 :(得分:2)

首先,关于vector.size(),请参阅 this SO question。另外,我还没有看到std::vector::size()不是O(1)的实现。

if (x != 0) camX += x;cmp和后续jne会比简单地添加变量x更慢,无论如何。 编辑:除非您预计camX

上的缓存未命中率超过50%

答案 3 :(得分:1)

第一个可能是悲观,0的检查可能比添加慢。最重要的是,在致电D3DXMatrixTranslation之前的检查中,您使用的是|,而不是短路逻辑或||。由于函数调用之前的检查可能节省了时间(甚至在语义上是必需的),因此将整个代码包装在该检查中,

void Renderer::SetCamera(FLOAT x, FLOAT y, FLOAT z) {

    if (x != 0 || y != 0 || z != 0) {
        camX += x;
        camY += y;
        camZ += z;
        D3DXMatrixTranslation(&w, camX, camY, camZ);
    }
}

如果xyz都为零,则无需执行任何操作,否则,请执行所有操作。

对于第二种情况,编译器可以在循环外提升vector.size(),如果它可以确定在循环运行时大小不会改变。如果编译器无法确定,则不得在循环外提升size()计算。

当你知道尺寸没有改变时,你自己这样做是好的做法。