Math.pow yields different result depending on java

2019-03-22 11:54发布

问题:

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).

回答1:

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!



回答2:

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.



回答3:

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?



回答4:

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.