C++ 这是微优化的一种形式吗?

C++ Is this a form of micro optimization

本文关键字:一种 优化 C++      更新时间:2023-10-16
这是

微优化,还是根本不是优化?

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,至于第二个问题,它似乎是编译器可以优化的东西,但我只是不确定。

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

由于 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,也不会是优化,因为在值可能大多数时候不为零时进行检查和分支是更多的工作。

其次,更重要的是,它们是浮动的。这意味着除了你不应该直接将它们与 0 进行比较这一事实之外,它们基本上几乎永远不会完全等于 0。因此,if是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为真(它不会计算其余部分(,那么它会短路,但|这种情况不会发生。

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

另一方面,在进行转换之前,确保至少有一个组件不为零似乎是合理的。

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

首先,关于vector.size(),请参阅这个问题。附带说明一下,我还没有看到std::vector::size()不是 O(1( 的实现。

if (x != 0) camX += x;这种cmp和随之而来的jne无论如何都会比简单地添加变量x慢。编辑:除非您预计camX缓存未命中率超过 50

%

第一个可能是悲观的,对 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()计算提升到循环之外。

当您知道大小不变时,自己这样做是一种很好的做法。