I'm running the following code on a JDK Version 1.7.0_60:
System.out.println(Math.pow(1.5476348320352065, (0.3333333333333333)));
The result is: 1.1567055833133086
I'm running exactly the same code on a JDK Version 1.7.0.
The result is: 1.1567055833133089
I understand that double is not infinitely precise, but was there a change in the java spec that causes the difference?
PS: Because we use a legacy system, Big Decimal is not an option.
Edit: I was able to track down the time of the change: It was introduced in the JDK Version 1.7.0_40 (as compared to Version 1.7.0_25).
but was there a change in the java spec that causes the difference?
No.* According to the Javadocs for Math.pow
, a difference of up to one ULP (Unit in the Last Place) is permitted. If we take a look at your two values:
System.out.printf("%016x\n", Double.doubleToLongBits(1.1567055833133086));
System.out.printf("%016x\n", Double.doubleToLongBits(1.1567055833133089));
we get:
3ff281ddb6b6e675
3ff281ddb6b6e676
which indeed differ by one ULP.
What you're seeing is probably due to slight differences in the sequence of floating-point instructions used by the JDK/JVM to implement these operations.
* At least, not so far as I know!
There was no change in the spec, but there have been some changes in the hotspot optimizer that might (!) be related to this.
I dug up these code parts:
- From update 25: vm/opto/library_call.cpp : inline_pow
- From update 40: vm/opto/library_call.cpp : inline_pow
(these are not exactly the versions where these changes have been introduced, I just picked them because of the version information that you provided).
The changes (and what the code is doing at all) are far beyond what I can analyze in reasonable time, but maybe someone finds this reference interesting or useful.
If you want repeatable floating point values between JVMs you can use the strictfp keyword, see following question When should I use the "strictfp" keyword in java?
To produce consistent results between all Java versions, the solution was to use StrictMath.pow()
instead of Math.pow()
.
For background information on what might cause the difference, refer to this answer.