2

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

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

4 回答 4

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

其次,更重要的是,它们是浮动的。这意味着除了您不应该直接将它们与 0 进行比较之外,它们基本上几乎永远不会完全等于 0。所以ifs 是 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|

于 2013-04-29T16:54:32.753 回答
2

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

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

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

于 2013-04-29T16:54:18.847 回答
2

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

if (x != 0) camX += x;然而,无论如何,这cmp和随之而来jne的将比简单地添加变量要慢x编辑:除非您期望超过 50% 的缓存未命中camX

于 2013-04-29T16:55:10.013 回答
1

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

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);
    }
}

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

vector.size()其次,如果编译器可以确定循环运行时大小没有改变,则编译器可以提升循环外部。如果编译器无法确定,则不得将size()计算提升到循环之外。

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

于 2013-04-29T16:58:33.177 回答