JDK-4306749 : java.lang.Math.cos/sin results are not within 1ulp on Win98
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: solaris_2.6,windows_95,windows_nt
  • CPU: x86,sparc
  • Submitted: 2000-01-24
  • Updated: 2001-05-24
  • Resolved: 2001-05-24
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description
The javadoc for java.lang.Math.sin/cos says:

------
      A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic.
------

The Math.cos(x) is not within 1 ulp from StrictMath.cos(x) on Win98
where x = Double.longBitsToDouble(0x3ff921f0d7e968a9L)
or    x = Double.longBitsToDouble(0xbcc5cb3b399d747fL) 

The Math.sin(x) is not within 1 ulp from StrictMath.sin(x) on Win98
where x =  Double.longBitsToDouble(0xc01921fb54442d18L)

Below you can see the test run of the example on Solaris and on
win98. The Solaris results are correct and are the same for Math
and StrictMath. The win98 results differ between Math and StrictMath.
The StrictMath result on win98 and on Solaris are the same thing,
which is the correct result.
However, the win98 Math sin/cos return values that are not winthin 
1 ulp (in binary) from the correct result.

Inside the test example in comments you will find the output of the
JCK test run, which shows results in hexadecimal notation and it is
clear that the "Expected" and "Got" results differ more than 1 ulp. 

public class Test {
    public static void main(String [] args) throws Exception {

//this is the output from JCK test:
//cos failed for 3ff921f0d7e968a9 Expected 3ee4f8b588dd0ce3 +/- 1 ulp Got: 3ee4f8b588dd0ce1
//cos failed for 3ff921fb54442d1b Expected bcc5cb3b399d747f +/- 1 ulp Got: bcc5cb4000000000
//sin failed for c01921fb54442d18 Expected 3cb1a62633145c07 +/- 1 ulp Got: 3cb1a60000000000

        System.out.println("x1 = " + Double.longBitsToDouble(0x3ff921f0d7e968a9L));
        System.out.println("x2 = " + Double.longBitsToDouble(0x3ff921fb54442d1bL));
        System.out.println("cos(x1) = " + Math.cos(Double.longBitsToDouble(0x3ff921f0d7e968a9L)));
        System.out.println("cos(x2) = " + Math.cos(Double.longBitsToDouble(0x3ff921fb54442d1bL)));
        System.out.println("cos(x1) = " + StrictMath.cos(Double.longBitsToDouble(0x3ff921f0d7e968a9L)));
        System.out.println("cos(x2) = " + StrictMath.cos(Double.longBitsToDouble(0x3ff921fb54442d1bL)));
        System.out.println("x3 = " + Double.longBitsToDouble(0xc01921fb54442d18L));
        System.out.println("sin(x3) = " + Math.sin(Double.longBitsToDouble(0xc01921fb54442d18L)));
        System.out.println("sin(x3) = " + StrictMath.sin(Double.longBitsToDouble(0xc01921fb54442d18L)));

    }
}
solaris run:
-----
x1 = 1.5707863267948972
x2 = 1.5707963267948972
cos(x1) = 9.999999999293945E-6
cos(x2) = -6.049014748177263E-16
cos(x1) = 9.999999999293945E-6
cos(x2) = -6.049014748177263E-16
x3 = -6.283185307179586
sin(x3) = 2.4492935982947064E-16
sin(x3) = 2.4492935982947064E-16

win 98 run:
-------
x1 = 1.5707863267948972
x2 = 1.5707963267948972
cos(x1) = 9.999999999293941E-6
cos(x2) = -6.049034970839751E-16
cos(x1) = 9.999999999293945E-6
cos(x2) = -6.049014748177263E-16
x3 = -6.283185307179586
sin(x3) = 2.4492127076447545E-16
sin(x3) = 2.4492935982947064E-16

 

Comments
EVALUATION I cannot reproduce the results on my machine but the results described are off by more than 1 ulp. I have heard that a fix went into hotspot that may have eliminated this problem. Can this still be reproduced? What hardware was this result generated on? michael.mccloskey@eng 2000-01-25 ###@###.### 2000-01-25 I use win95 RILEY2 machine in Cupertino and it is still reproducible with the latest kestrel build "T". Please e-mail me at sko@eng if you want to see it. ------------------------ This is not a Win98 bug, but a general Intel CPU related problem. This problem will show up on all HotSpot implementations running on an Intel x86 CPU, be it a Windows version or Solaris on x86. The problem is that the Intel CPU instructions fsin and fcos do not deliver a result within 1ulp of the correct result for some arguments in the allowed range. Note that this is contrary to what Intel is claiming in its manuals. Further analysis shows that fsin & fcos are within 1ulp (emprically) for arguments within the range [0.0, pi/4] - however the results are significantly off the correct value for other arguments where the functions sin and cosine are "steep" (i.e. are crossing the x axis). The problem stems from the fact that internally, the Intel CPU is using only a 66 bit value of pi for argument reduction. Since sin(x) = sin(x mod 2*pi), a value of x' = x mod 2*pi that is slightly off the correct value due to slightly incorrect value of pi will lead to a error in the result of sin(x') that is the bigger, the steeper the function sin is in the neighborhood of x'. The same is true for cos. Around 0, the results are correct since no argument reduction is necessary. One can solve the problem by implementing argument reduction manually, such a solution should still be faster than using StrictMath. However, that is not an easy thing to do and requires deep numerical knowledge. It also will slow down the execution of sin and cos considerably. Please see the attached Java program (Attachments) for a test program and some numbers confirming the above statements. robert.griesemer@Eng 2000-02-28
28-02-2000