3

考虑 Java 中的以下方法:

public static boolean expensiveComputation() {
    for (int i = 0; i < Integer.MAX_VALUE; ++i);
    return false;
}

以及以下主要方法:

public static void main(String[] args) {
    boolean b = false;
    if (expensiveComputation() && b) {
    }
}

逻辑合取(与 && 相同)是可交换操作。那么为什么编译器不将 if 语句代码优化为等效的:

if (b && expensiveComputation()) {
}

使用短路评估有哪些好处?

此外,编译器是否尝试进行其他逻辑简化或布尔值排列以生成更快的代码?如果不是,为什么?当然,一些优化会非常困难,但我的例子并不简单?调用方法应该总是比读取布尔值慢,对吧?

先感谢您。

4

5 回答 5

17

它不会这样做,因为昂贵的计算()可能会产生改变程序状态的副作用。这意味着计算布尔语句中的表达式的顺序(expensiveComputation() 和 b)很重要。您不希望编译器将错误优化到已编译的程序中,对吗?

例如,如果代码是这样的

public static boolean expensiveComputation() {
        for (int i = 0; i < Integer.MAX_VALUE; ++i);
        b = false;
        return false;
}

public static boolean b = true;
public static void main(String[] args) {
        if (expensiveComputation() || b) {
        // do stuff
        }
}

在这里,如果编译器执行了您的优化,那么//do stuff当您通过查看代码时不希望它运行时,它将运行(因为最初为 true 的 b 首先被评估)。

于 2009-08-28T17:55:40.903 回答
8

因为expensiveComputation()可能有副作用。

由于 Java 的目标不是成为一种功能纯语言,因此它不会阻止程序员编写具有副作用的方法。因此,编译器分析功能纯度可能没有太多价值。然后,像您假设的优化在实践中不太可能非常有价值,因为expensiveComputation()通常需要执行才能获得副作用。

当然,对于程序员来说,b如果他们期望它是错误的并且明确地想要避免昂贵的计算,那么很容易把它放在第一位。

于 2009-08-28T17:55:44.757 回答
2

实际上,一些编译器可以像您建议的那样优化程序,它只需要确保该函数没有副作用。GCC 有一个编译器指令,您可以使用它来注释函数以表明它没有副作用,然后编译器可以在优化时使用它。Java 可能有类似的东西。

一个经典的例子是

for(ii = 0; strlen(s) > ii; ii++) < 做某事 >

优化为

n = strlen(s); for(ii = 0; n > ii; ii++) <做某事>

由 GCC 优化级别 2,至少在我的机器上。

于 2009-08-29T09:13:16.023 回答
0

如果您足够频繁地运行代码,编译器将对此进行优化,可能是通过内联方法并简化生成的布尔表达式(但很可能不是通过重新排序 && 的参数)。

您可以通过定时循环重复此代码的一百万次迭代来对此进行基准测试。第一次或两次迭代比以下迭代慢得多。

于 2009-08-29T08:42:55.177 回答
0

我使用的 java 版本优化了表达式中的 a,a && b但不优化 b。

即,如果 a 为假,则 b 不会被评估,但如果 b 为假,则不会执行此操作。

当我在网站表单中实现验证时,我发现了这一点:我用一系列布尔方法创建了要在网页上显示的消息。我希望页面中输入错误的字段会突出显示,但是由于 Java 的速度破解,代码仅在发现第一个错误字段之前执行。在那之后,Java 肯定想到了“假 && 任何东西总是假”之类的东西,并跳过了其余的验证方法。

我想,作为对您问题的直接回答,如果您进行这样的优化,您的程序运行速度可能会比它可能运行得慢。但是,其他人的程序将完全中断,因为他们假设了未优化的行为,例如其他答案中提到的副作用。

不幸的是,智能决策很难自动化,特别是对于命令式语言(C、C++、Java、Python,...即普通语言)。

于 2015-04-24T15:35:23.077 回答