4

下面是我需要优化和计划的代码,它会很好地转移到switch构造。但我可以比较以防万一。所以我打算将比较(len > 3)作为默认情况。

如果我将比较部分(len > 3)作为默认情况,并将默认情况添加开关中的第一个,会更快吗?

或者我怎样才能将下面的代码作为 switch 语句?

if ( len > 3 ) {
    // Which will happen more often;
}
else if ( len == 3 ) {
    // Next case which may occur often;

} else if ( len == 2 ) {
    // The next priority case;

} else {
    // And this case occurs rarely;

}
4

6 回答 6

6

可能不是。if...else和都是switch...case高级构造。让你慢下来的是分支预测。您的预测越好,您的代码运行速度就越快。就像您写的那样,您应该将最常见的情况放在 first 中if, second 中,依此类推。else if因为switch结果取决于内部编译器实现,尽管您自己的顺序可以重新排序案例。实际上应该为发生较少的default情况保留 ,因为在回退到 之前必须检查其余条件default

总而言之,if...else只要您以正确的顺序设置条件,性能方面的使用就是最佳的。关于switch...case它是特定于编译器的,并且取决于应用的优化。

另请注意,它switch...caseif...else仅支持简单的值比较受到更多限制。

于 2012-12-28T07:32:53.073 回答
3

尽管您已经接受了可能是最好的答案,但我想提供一个替代方案。

请注意,标准警告适用 - 优化不是优化,除非您已经分析了您的代码。

但是,如果您遇到与分支相关的较差性能,您可以减少或消除它们。您的代码具有一个或多个不等式比较并不是一个障碍 - 您可以将您的案例减少到一组直接等式,并在必要时使用它来索引表,而不是完全分支。

void doSomething(int len)
{
    static const char* str[] =
    {   "%2d > 3\n",
        "%2d < 2\n",
        "%2d = 2\n",
        "%2d = 3\n"
    };

    int m1 = (len-2)>>31;
    int m2 = (len-4)>>31;

    int r = (len & m2 & ~m1) + !!m1;

    printf(str[r],len); 
}

请注意,此代码做出了几个在实践中可能不成立的假设,但由于我们正在做出疯狂的假设,即这甚至需要首先优化......

另外,请注意,如果更多地了解输入参数的实际范围和类型,以及实际需要采取的实际操作,则可能会进行更好的优化。

于 2012-12-28T08:57:23.140 回答
2

您不能将比较移动到switch语句中......它对其选择使用单一检查.. 即,

switch (len) {

    case 1:
        // Do case 1 stuff here
    break;

    case 2:
        // Do case 2 stuff here
    break;

    case 3:
        // Do case 3 stuff here
    break;
}

使用中断来防止 case 语句相互冲突在这里阅读更多。

您的代码已“优化”,因为它将处于当前状态......

于 2012-12-28T07:28:30.267 回答
1

如果您担心速度,事实是您的if...elseorswitch...case语句不会对您的应用程序速度产生真正的影响,除非您有数百条语句。你失去速度的地方是在你的迭代或循环中。要具体回答您的问题,您不能将您的if...else陈述转换为先出现的switch...case陈述default;但是话虽如此,如果您确实转换为a,switch...case那么您会认为它们以相同的速度运行(差异太小而无法被传统的基准测试工具拾取)。

于 2012-12-28T07:42:26.313 回答
1

您将知道的唯一方法是使用您的编译器对其进行基准测试。如果性能是一个问题,您应该使用该选项为编译器提供分析器输出,并让它决定;它通常会找到最佳解决方案。(请注意,即使在特定架构上,如英特尔,机器指令方面的最佳解决方案也可能因处理器而异。)

在您的情况下,开关可能如下所示:

switch ( len ) {
case 2:
    //  ...
    break;

case 3:
    //  ...
    break;

default:
    if ( len > 3 ) {
        // ...
    } else {
        // ...
    }
}

只有两个有效的案例,编译器没有太多的工作。一个典型的实现(没有极端优化)会进行边界检查,然后对两个显式情况进行表查找。然后,任何体面的编译器都会发现您的default情况下的比较对应于它已经完成的边界检查之一,而不是重复它。但是只有两种情况,与这两种比较相比,跳转表可能不会产生显着差异,尤其是在最常见的情况下你会越界。

除非您有实际的分析器信息表明这是代码中的瓶颈,否则我不会担心。获得这些信息后,您可以分析不同的变体以查看哪个更快,但我怀疑如果您使用最大优化并将分析信息反馈回编译器,则不会有任何区别。

于 2012-12-28T10:50:26.350 回答
0

您可以在案例中使用范围:

switch (len) {
  case 3 ... INT_MAX:
    // ...
    break;
  case 2:
    // ...
    break;
  default:
    // ...
    break;
 }

但这是 GCC 提供的扩展......

于 2012-12-28T07:39:37.613 回答