C :使用goto加速循环

C++: speeding up a for-loop using goto?

本文关键字:加速 循环 goto 使用      更新时间:2023-10-16

在以下 for -loop中,如果conditionAconditionBconditionC我什么都不做,所有这些都对true进行了评估。

for (int i = 0; i < imax; ++i) {
    bool conditionA;
    // evaluate conditionA
    bool conditionB;
    // evaluate conditionB
    bool conditionC;
    // evaluate conditionC
    if (conditionA && conditionB && conditionC) continue;
    // do something
}

如果conditonA评估false,则不必评估conditionBconditionC。因此,似乎我可以通过以下方式编写循环加快循环。

for (int i = 0; i < imax; ++i) {
    bool conditionA;
    // evaluate conditionA
    if (conditionA) {
        bool conditionB;
        // evaluate conditionB
        if (conditionB) {
            bool conditionC;
            // evaluate conditionC
            if (conditionC) continue;
        }
    }   
    // do something
}

现在,这看起来很丑陋,乍一看尚不清楚。似乎使用臭名昭著的goto代码变得更加优雅:

for (int i = 0; i < imax; ++i) {
    bool conditionA;
    // evaluate conditionA
    if (!conditionA) goto doSomething;
    bool conditionB;
    // evaluate conditionB
    if (!conditionB) goto doSomething;
    bool conditionC;
    // evaluate conditionC
    if (conditionC) continue;
    doSomething:
    // do something
}

此功能是加速循环的方法,还是编译器足够聪明,以至于代码的第一个版本实际上与第二版和第三版一样快?如果不是,是否有比使用goto更好的选择?

i会将条件的评估移至单独的功能,然后做:

for (int i = 0; i < imax; ++i) {
    if (conditionA() && conditionB() && conditionC()) continue;
    // do something
}

如果conditionA返回falseconditionB将永远不会被调用,等等。

这也将使您的功能更短,更简洁,将职责划分为其他功能。

如果您没有充分的理由进行这样的"提早出口",则可以避免完全使用continue

for (int i = 0; i < imax; ++i) {
    if (!(conditionA() && conditionB() && conditionC())) {
      // do something
    }
}

或使用de Morgan的定律获取!conditionA() || !conditionB() || !conditionC-无论您喜欢哪个。

在尝试加快一些速度之前,请查阅循环确实是瓶颈。如果不是这样,请留出代码可读且可维护(而不是也许略快,也许 slow shouts 肯定是错误的且难以理解的混乱),并将其留给您的编译器的功能加快事情的速度。

如果循环是瓶颈,请尝试想到的一切, profile it it,并比较结果。没有人可以肯定地说您的编译器可能会优化什么。

在微观性能优化时,除了您的探查器以外,永远不要相信任何人。编译器在优化和如何优化方面有所不同,并且人类在预测这些优化的节省方面特别糟糕。

但是,如果条件不太复杂,我敢打赌,编译器将无论如何都会优化布尔变量,并留下

之类的东西
for (int i = 0; i < imax; ++i) {
  if(evalConditionA() && evalConditionB() && evalConditionC())
    continue;
  doSomething:
}

您总是能做的就是将任何条件的概率提高到任何情况下,并将最有可能触发短路评估的一个条件放在第一个条件下,因此其他情况不需要经常进行评估。

一如既往,如果您想知道性能,只需做一个基准即可。否则,我认为最好的解决方案确实取决于您的上下文。例如,如果您可以在估值或单独的功能(或最坏的情况下为宏)中,您的第一个解决方案是最好的:

for (int i = 0; i < imax; ++i) {
    if (! (evaluate conditionA) && (evaluate conditionB) && (evaluate conditionC)) {
        // do something
    }
}

然后,懒惰的评估将提供帮助,根据您的工作,您的编译器可能能够通过一些优化选项优化评估。

我还建议您不要使用if (condition) continue;,而是使用if (!condition) { /* do something */ },这有助于更好地理解该算法。别忘了有一天有人会读您的代码,并且某人可能是您!

c 编译器(至少是Visual Studio)已经完成了您的需求。

if( bCondA && bCondB && bCondC )

如果bconda == false,则未经验证。对于所有编译器,都应该是正确的。