在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) {
}
}
逻辑连词(与&amp;&amp;)相同的是commutative operation。那么为什么编译器不会将if语句代码优化为等效代码:
if (b && expensiveComputation()) {
}
哪个有benefits of using short-circuit evaluation?
此外,编译器是否尝试对布尔值进行其他逻辑简化或置换以生成更快的代码?如果没有,为什么?当然,一些优化会非常困难,但我的例子并不简单?调用方法应该总是比读取布尔值慢,对吗?
提前谢谢。
答案 0 :(得分:17)
它没有这样做,因为expensiveComputation()可能有副作用,改变程序的状态。这意味着评估布尔语句中表达式的顺序(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
将在你不期望它通过查看代码时运行(因为b,最初是真的,首先被评估)。 / p>
答案 1 :(得分:8)
因为expensiveComputation()
可能有副作用。
由于Java并不是一种功能纯粹的语言,因此它不会阻止程序员编写具有副作用的方法。因此,编译器分析功能纯度可能没有太多价值。然后,像你这样的优化在实践中不太可能非常有价值,因为通常需要执行expensiveComputation()
来获得副作用。
当然,对于程序员来说,如果b
期望它是假的并且明确地希望避免昂贵的计算,那么很容易将{{1}}放在首位。
答案 2 :(得分:2)
实际上,一些编译器可以优化你建议的程序,它只需要确保该函数没有副作用。 GCC有一个编译器指令,您可以使用它来注释函数,以显示它没有副作用,编译器可能会在优化时使用这些副作用。 Java可能有类似的东西。
一个典型的例子是
表示(ii = 0; strlen(s)> ii; ii ++)&lt;做点什么&gt;
被优化为
n = strlen(s);对于(ii = 0; n> ii; ii ++)&lt;做点什么&gt;
由GCC进行优化级别2,至少在我的机器上。
答案 3 :(得分:0)
如果您经常运行代码,编译器将对此进行优化,可能是通过内联方法并简化生成的布尔表达式(但很可能不是通过重新排序&amp;&amp;的参数)。
您可以通过计算重复执行此代码的百万次迭代的循环来对此进行基准测试。第一次或第二次迭代比以下慢得多。
答案 4 :(得分:0)
我使用的java版本在表达式a && b
中优化a,但不在b中优化。
即。如果a为false,则b不会被评估,但如果b为false则不会执行此操作。
当我在网站表单中实现验证时,我发现了这一点:我创建了一些消息,以一系列布尔方法显示在网页上。 我期望页面中错误输入的字段突出显示,但是,由于Java的速度黑客,代码只在第一个不正确的字段被发现之前执行。在那之后,Java必须考虑像&#34; false&amp;&amp;什么都是假的&#34;并跳过了剩余的验证方法。
我想,作为对你的问题的直接回答,如果你做这样的优化,你的程序可能会运行得比它慢。但是,其他人的程序会完全破解,因为他们已经采取了非优化行为,就像其他答案中提到的副作用一样。
不幸的是,自动化智能决策很困难,特别是使用命令式语言(C,C ++,Java,Python,......,即普通语言)。