In C++ optimizers you can specify the use of fast floating point arithmetic instead of precise floating point arithmetic. The difference is that in fast mode it will do optimizations that would apply to real world math, but may not produce the correct results when done on a computer.
An example of this can be shown using GodBolt using the following code and the -O2
optimization. If you are using clang or gcc you can put in the -ffast-math
parameter to view what the code looks like with these optimizations.
double mulBy6DivBy12(double x)
{ return 6 * x / 12; }
double divBy2(double x)
{ return x / 2; }
Without the -ffast-math
parameter it will generate a multiply and divide operation in the mulBy6DivBy12
function, with it on the two functions will look the same.
What I want to know is at runtime, when being processed by the JIT does it do these potentially unsafe optimizations?
There are two interesting statements in the Java Language Specification.
The first is a broad one in JLS section 15.7:
15.7. Evaluation Order
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
This is already a fully guarantee; even though execution may be in any order, they have to appear to be in the left-to-right evaluation order. A re-ordering of the floating point operations would break that appearance, so it's not allowed.
Secondly, there is a guarantee specifically for floating point operations in JLS section 4.2.4:
The Java programming language requires that floating-point arithmetic behave as if every floating-point operator rounded its floating-point result to the result precision. Inexact results must be rounded to the representable value nearest to the infinitely precise result; if the two nearest representable values are equally near, the one with its least significant bit zero is chosen. This is the IEEE 754 standard's default rounding mode known as round to nearest.
This clarifies exactly how each (left-to-right) operation should round its results. This also disallows any reordering that changes the result of the calculation from the result that you get if you perform the operations in left-to-right order.