Will the compiler optimize repeated math computations?

The answer is yes. This is called Common Subexpression Elimination and is a standard (and powerful) compiler optimization used in Java, C/C++ and others...

This page confirms that the HotSpot JVM will do this optimization.


That said, whether or not the compiler/run-time will be able to do this optimization when you expect it to is another story. So I usually prefer to do these optimizations myself if it also enhances readability.

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

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

The compiler may perform such optimizations. Whether it actually does depends on the answers to following:

Is the compiler allowed to do this by the JLS?

In some cases it is not. For instance if prevX was a volatile instance variable, then it must be fetched from memory each time the source code says it is used. Another case is where the common subexpression involves a method call with an observable side-effect; i.e. where something else in program might be able to tell if the method is called once or twice.

Is the compiler capable of doing this?

A compiler needs to analyze the code to detect common subexpressions that could legally be optimized. There two issues here:

  • Is the compiler capable of performing the necessary reasoning? For instance, one could hypothesize a compiler that can determine that a specific method call will be side-effect free and that therefore can be optimized. However, building a compiler that is actually capable of doing this is ... and interesting problem.

  • Is the optimization worthwhile? There is a trade-off between the cost of performing an optimization and the benefits. It is not a straight forward trade-off. It needs to take into account the cost of looking to see if an optimization can be performed ... when it actually can't. In other words, the impact on compilation time. (Bear and mind that in Java the optimizations are mostly done at runtime by the JIT compiler ... so this impacts on application performance.)

In a simple example like yours, the optimization is legal (modulo volatile) and one should expect a half-decent JIT compiler to perform it.


The other question is whether you should try to help the compiler by evaluating the common expressions explicitly your code and assigning the results to temporaries.

IMO, the answer is generally no.

  • A good compiler will probably do as good as job as you at this. And if it doesn't, then the next generation may do.

  • The code probably doesn't warrant hand optimization. Unless you've profiled your code to determine where the bottlenecks are, your hand optimizations stand a good chance of being irrelevant to actual application performance ... and a waste of your time.

  • There is a chance that you will stuff it up; e.g. by forgetting that a method call has an important side-effect or that a variable is volatile for a good reason.

On the other hand, if the rewrite makes your code more readable, that's a good reason to do it.


In general, "yes" - the compiler will optimize the code if it can, and the HotSpot JVM can also improve repeatedly-executed code blocks.

In this case however, you would be better to refactor the code like this:

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

which avoids one division operation if x > y.

Tags:

Java