3

我有一个条件语句expensive_foo(),在 99.9% 的情况下它是错误的。我有一个条件语句bar,在约 50% 的情况下是正确的。

如果两个陈述都是真的,我希望采取一些行动。所以我几乎肯定知道那expensive_foo()是假的,我只想检查它是否bar是真的。

下面的代码是否会检查expensive_foo()ONLY ifbar为真?还是expensive_foo()每次都会检查?

if ( bar && expensive_foo() )
{
    ...
}

或者我需要制作这样的结构:

if ( bar )
{
    if ( expensive_foo() )
    {
        ...
    }
}
4

5 回答 5

5

逻辑 AND 运算符&&是短路的,这意味着当且仅当第一个操作数被评估为 时,保证第二个操作数被评估true。条件if (bar && foo)if (bar) if (foo)是相同的。

鉴于foo计算成本很高,您几乎绝对应该bar先检查一下。尽管bar分支预测器不能很好地预测,但与foo.

因此,结构可能应该是:

if (bar)
{
    if (bool const foo = compute())   // expensive
    {
        // ...
    }
}

请注意,所有这些结构都意味着我们可能会或可能不会调用compute(). 如果您无条件地需要函数调用,那么您应该将其作为第一个检查。在这种情况下,应该利用对结果的成功分支预测。

于 2012-09-14T12:50:52.290 回答
2

两个代码都只会检查是否foobar真。在第一种情况下,这是由语言惰性布尔表达式评估来保证的(实际上可以在某些编译器中显式关闭,但默认情况下是打开的)。

于 2012-09-14T12:51:50.190 回答
1

其他答案很好,但我质疑这个前提。

如果您查询的谓词在 99.9% 的情况下为假,这类似于在 2000 个条目的列表中进行线性搜索,您要查找的项目可能以大致相等的概率出现在任何地方。

在这种情况下,通常人们会尝试以不同的方式组织列表,以便进行 O(logN)(或更好)搜索而不是 O(N)。我不知道你能不能做到这一点,但那是我要关注的地方。

当以高度偏斜的概率提出问题时,如果可以取消偏斜,那可能是一个很大的加速机会。(假设大部分时间都花在了这个活动上。如果不是,那么这一点就没有实际意义了。)

于 2012-09-14T14:38:46.613 回答
1

如果两者的优化装配不完全相同,我会感到惊讶。如果 bar 为 false,则永远不会调用昂贵的 foo()。

于 2012-09-14T16:31:25.117 回答
1

我看到一条评论说编译器可以重新排序操作,我倾向于这种观点。改进顺序程序的自动并行化的努力产生了更好的编译器,它有助于程序员避免从他们的程序中执行复杂的并行化例程。编译器可以对操作重新排序,前提是重新排序不违反/恶化局部性,或者在广义上不违反程序的实际意图。

但我怀疑编译器会尝试重新排序条件语句,例如:

  if ( bar && expensive_foo() )

如果把成本较低的布尔函数放在开头,肯定可以节省一些时间。

于 2012-09-14T23:37:05.477 回答