编译器会优化重复的数学计算吗?

问题描述 投票:6回答:3

Java编译器将优化简单的重复数学运算,例如:

if (prevX / width != curX / width) {
    // Do something with prevX / width value
} else {
    // Do something with curX / width value
}

我知道我可以将结果分配给if语句之前的变量,然后返回变量,但这有点麻烦。如果编译器自动识别出正在执行相同的计算,并将结果自行缓存到临时变量中,我宁愿遵守上述约定。

*编辑-我是个白痴。我试图过多地简单/抽象我的问题。它不是那么简单:if(x> y)

java
3个回答
7
投票

答案是肯定的。这称为Common Subexpression Elimination,是Java,C / C ++和其他语言中使用的标准(且功能强大)编译器优化...

[This page确认HotSpot JVM将进行此优化。


就是说,编译器/运行时是否能够在您期望的时候进行此优化是另一回事。因此,如果可以提高可读性,我通常更愿意自己进行这些优化。

double xw = x / width;
double yw = y / width;

if (xw > yw) {
    return xw;
} else {
    return yw;
}

3
投票

编译器可以执行此类优化。它是否确实取决于以下答案:

由JLS编译器allowed执行此操作吗?

在某些情况下不是。例如,如果prevXvolatile实例变量,那么每次源代码说它被使用时,都必须从内存中获取它。另一种情况是,通用子表达式涉及具有可观察到的副作用的方法调用;即程序might中的其他内容可以告诉您该方法是调用一次还是两次。

编译器有能力]执行此操作吗?

编译器需要分析代码以检测可以合法优化的常见子表达式。这里有两个问题:

  • 编译器是否能够执行必要的推理?例如,可以假设一个编译器可以确定特定的方法调用是无副作用的,因此可以对其进行优化。但是,构建实际上能够执行此操作的编译器是...和有趣的问题。

  • 优化值得吗?在执行优化的成本和收益之间需要权衡。这不是直接的权衡。它需要考虑寻找优化是否可以执行的成本,而实际上却不能。换句话说,对编译时间的影响。 (请注意,在Java中,优化通常是在运行时由JIT编译器完成的,因此会影响应用程序性能。)

  • 在像您这样的简单示例中,优化是合法的(模数volatile),应该期望有一个像样的JIT编译器来执行它。


另一个问题是您是否应该通过明确评估公共表达式并将代码分配给临时变量来尝试帮助编译器

IMO,答案通常是否。

  • 一个好的编译器在此方面可能会像您一样出色。如果没有,那么下一代可能会这样做。

  • 该代码可能不需要手动优化。除非您已对代码进行概要分析以确定瓶颈所在,否则您的手部优化很可能会与实际应用程序性能无关

  • ...并且浪费时间。
  • 有可能您将其塞满;例如通过forgetting

  • 表示方法调用具有重要的副作用,或者有充分的理由说明变量为volatile

    另一方面,如果重写使您的代码更具可读性],那么这样做是一个很好的理由。

通常,“是”-编译器将在可能的情况下优化代码,并且HotSpot JVM也可以改善重复执行的代码块。

但是,在这种情况下,您最好像这样重构代码:

if (x > y)
    return x / width;
return y / width;

如果x > y,则避免一个除法运算。


2
投票

通常,“是”-编译器将在可能的情况下优化代码,并且HotSpot JVM也可以改善重复执行的代码块。

© www.soinside.com 2019 - 2024. All rights reserved.