Jump to content
Excelsior Forums
DanielEH

Degraded arithmetic precision caused by Jet

Recommended Posts

I write scientific software that computes several statistics. I noticed that the source version was returning a different value

than the Jet compiled exe. I reproduced this with a simple test file (ArithmeticTest.java). I also implemented the test code with C++(ArithmeticTest.zip). The result was that the JVM (jdk 1.6.0_19) and C++ code returned the exact same result for kurtosis (1.8888010687715593). After compiling the test file with Jet 7.6 Pro, the test program reports a value of 1.8887956447048073. This is a difference of -5.424066751968937E-6, which seems beyond a double precision rounding problem.

Any insight would be appreciated,

Daniel

ArithmeticTest.java

ArithmeticTest.zip

Share this post


Link to post
Share on other sites

The difference is provoked by Math.pow as can be seen from the following sample:

-----------------------

public class TestPow {

 public static void main(String[] args) {

   double center2 = 539.8411439729485;

   double expectedPow = 8.49305477211384E10;

   double computedPow = Math.pow(center2,4);

   if (computedPow != expectedPow){
     System.out.println("Computed value is: "+ computedPow);
     System.out.println("Expected value is: "+ expectedPow);

   } else {

     System.out.println("value is exact!");

   }
}

------------------------

We will keep you posted on whether this behavior complies with the Java Language specification.

Share this post


Link to post
Share on other sites

We have investigated this case and found that the result is correct.

According to the Java SE Platform specification, an implementation of the Math.pow method must meet the following conditions:

  1. The computed result must be within 1 ulp of the exact result.
  2. Results must be semi-monotonic.

The Excelsior JET's implementation satisfies both requirements for the given case. You can get convinced of that as follows:

import java.math.*;

public class TestPow {

   static String dump(String name, double x) {
       return name + " is: " + x + " [0x" + Long.toHexString(Double.doubleToRawLongBits(x)) + "]";
   }

   static final double center2 = 539.8411439729485;

   static double expectedPow = 8.49305477211384E10;

   static double computedPow = Math.pow(center2,4);

   public static void test(String name, double x) throws Exception {
       System.out.println(dump(name, x));
       System.out.println(dump("pow("+name+",4)", Math.pow(x,4)));
   }

   public static void main(String[] args) throws Exception{
       System.out.println(dump("Computed value", computedPow));
       System.out.println(dump("Expected value", expectedPow));
       test("center2", center2);
       test("nextUp(.)", Math.nextUp(center2));
       test("nextDown(.)", Math.nextAfter(center2, center2 - Math.ulp(center2)));

       BigDecimal bd = new BigDecimal(center2);
       BigDecimal pw = bd.pow(4);
       System.out.println(dump("bd.pow(4)", pw.doubleValue()) + " ["+pw+"]");
   }
}

This code produces the following output:

Computed value is: 8.493054772113841E10 [0x4233c6415009236f] Expected value is: 8.49305477211384E10 [0x4233c6415009236e]

center2 is: 539.8411439729485 [0x4080debaa9b0f855]

pow(center2,4) is: 8.493054772113841E10 [0x4233c6415009236f]

nextUp(.) is: 539.8411439729487 [0x4080debaa9b0f856]

pow(nextUp(.),4) is: 8.493054772113847E10 [0x4233c64150092373]

nextDown(.) is: 539.8411439729484 [0x4080debaa9b0f854]

pow(nextDown(.),4) is: 8.493054772113834E10 [0x4233c6415009236a]

bd.pow(4) is: 8.493054772113841E10 [0x4233c6415009236f] [84930547721.1384061168474255729608117096367050849812000908913459116875846451244938040614330154648031034422639217321791880749071330905091773409189281895947942757629789412021636962890625]

Here we see that:

  1. Excelsior JET's computed value differs from that of HotSpot only in the least significant bit of mantissa.
  2. Excelsior JET's result is semi-monotonic at this point.
  3. The exact result (computed via BigDecimal) is between Excelsior JET's and HotSpot's results, so both are within 1 ulp of it.

Notice also that Excelsior JET's result is closer to the exact one.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×