JDK-4855837 : (bf) ByteBuffer.getDouble() does not always return correct value (linux)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.1
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2003-04-29
  • Updated: 2003-05-01
  • Resolved: 2003-05-01
Related Reports
Duplicate :  
Description

Name: nt126004			Date: 04/29/2003


FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode

FULL OPERATING SYSTEM VERSION :
glibc-2.2.4-21
kernel 2.4.10-4GB
distribution SuSE-release


ADDITIONAL OPERATING SYSTEMS :
Red Hat Linux



A DESCRIPTION OF THE PROBLEM :
When I use the getDouble() method to interpret part of a
ByteBuffer, using allocateDirect, as a double, the results I
get do not agree with the interpretation of the same set of
bytes from the ByteBuffer if I use a DataInputStream with a
ByteArrayInputStream.  This is not for every double value
that I have interpreted, only some of them.  Moreover, the
double with the different value that is interpreted by using
DataInputStream and ByteArrayInputStream matches the values
returned by getDouble() on other operating systems that I
have tried this on, such as Windows 2000 and Solaris 8.  The
problem only occurs on Linux.  I have tried this on Suse
Linux and Red Hat Linux and both have this problem.  Also,
this problem does not occur on Linux when the ByteBuffer is
allocated using allocate(), only when using allocateDirect().


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I've attached some code I used to read in some binary data
that exhibits these problems.  I used the same binary file
when I ran this code twice, once using getDouble() and once
using getMyDouble.  When I comment in the use of the
getMyDouble method (uses ByteArrayInputStream and
DataInputStream to get a double value), one of the values
that prints is not the same as when I use the getDouble()
method on the ByteBuffer.

The code includes a comment at the top with the uuencode
for the binary data that I used for the test case.  Cut and
paste from the comment from begin... to end, save as a file
and uudecode it to create the binary data for the program.
Pass the file name from the uudecode as a command line
argument to the test case program.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Note that the only item that is different is the value
of L2RawRange:

Here's the output of the program when I use getDouble:
Before L1CarrierPhase=
65,1,77,36,-50,-64,0,0,
Before L1RawRange=
63,-77,-73,-107,-122,-13,123,50,
Before L2CarrierPhase=
64,-6,25,96,93,0,0,0,
Before L2RawRange=
63,-77,-73,-106,33,125,-9,-1,
After L1CarrierPhase=
65,1,77,36,-50,-64,0,0,
After L1RawRange=
63,-77,-73,-107,-122,-13,123,50,
After L2CarrierPhase=
64,-6,25,96,93,0,0,0,
After L2RawRange=
63,-77,-73,-106,33,125,-9,-1,
L1CarrierPhase=141732.60095214844
L1RawRange=0.07702002091126017
L2CarrierPhase=106902.02270507812
L2RawRange=0.07702005689316137


Here's the output of the program when I use getMyDouble
(ByteArrayInputStream and DataInputStream).  These values
agree with result from getDouble() on Solaris and Windows:
Before L1CarrierPhase=
65,1,77,36,-50,-64,0,0,
Before L1RawRange=
63,-77,-73,-107,-122,-13,123,50,
Before L2CarrierPhase=
64,-6,25,96,93,0,0,0,
Before L2RawRange=
63,-77,-73,-106,33,125,-9,-1,
After L1CarrierPhase=
65,1,77,36,-50,-64,0,0,
After L1RawRange=
63,-77,-73,-107,-122,-13,123,50,
After L2CarrierPhase=
64,-6,25,96,93,0,0,0,
After L2RawRange=
63,-77,-73,-106,33,125,-9,-1,
L1CarrierPhase=141732.60095214844
L1RawRange=0.07702002091126017
L2CarrierPhase=106902.02270507812
L2RawRange=0.07702005689313295



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.*;
import java.nio.channels.*;

public class NIORead {

/* Binary input data as uuencoded data:

begin 644 NIObinary.dbl
M00%-),[````_L[>5AO-[,D#Z&6!=````/[.WEB%]]_\-"D$">8]ON```/[.W
M^^1^]/]`^^V.]V```#^SM_Q^'>B)#0I!;E(&PL0``#^R)GA7Q8<I06>7WRL@
,H``_LB9XTO7V?PT*
`
end

*/
    public static void main(String [] args) throws IOException {
        ByteBuffer buff = ByteBuffer.allocateDirect(150);
        FileInputStream fis = new FileInputStream(args[0]);
        FileChannel fcin = fis.getChannel();

        buff.limit(32);
        long numBytes = fcin.read(buff);


        printBytes("Before L1CarrierPhase",buff, 0, 8);
        printBytes("Before L1RawRange",buff, 8, 8);
        printBytes("Before L2CarrierPhase",buff, 16, 8);
        printBytes("Before L2RawRange",buff, 24, 8);
        double L1CarrierPhase = buff.getDouble(0);
        double L1RawRange = buff.getDouble(8);
        double L2CarrierPhase = buff.getDouble(16);
        double L2RawRange = buff.getDouble(24);
/*        double L1CarrierPhase = myGetDouble(buff,0);
        double L1RawRange = myGetDouble(buff,8);
        double L2CarrierPhase = myGetDouble(buff,16);
        double L2RawRange = myGetDouble(buff,24); */
        printBytes("After L1CarrierPhase",buff, 0, 8);
        printBytes("After L1RawRange",buff, 8, 8);
        printBytes("After L2CarrierPhase",buff, 16, 8);
        printBytes("After L2RawRange",buff, 24, 8);

        System.out.println ("L1CarrierPhase=" + L1CarrierPhase);
        System.out.println ("L1RawRange=" + L1RawRange);
        System.out.println ("L2CarrierPhase=" + L2CarrierPhase);
        System.out.println ("L2RawRange=" + L2RawRange);

        fcin.close();
        fis.close();

    }

    public static double myGetDouble(ByteBuffer buff, int offset) throws
java.io.IOException {
        byte [] dBytes = new byte[8];
        buff.position(offset);
        buff.get(dBytes);
        ByteArrayInputStream bais = new ByteArrayInputStream(dBytes);
        DataInputStream dis = new DataInputStream(
          new ByteArrayInputStream(dBytes));
        double dValue = dis.readDouble();
        dis.close();
        return dValue;
    }

    public static void printBytes(String label, ByteBuffer buff, int start, int
length) {
        byte [] dBytes = new byte[length];

        System.out.println(label + "=");
        int index = start;
        for (int i=0;i<dBytes.length;i++) {
            dBytes[i] = buff.get(index);
            System.out.print(Byte.toString(dBytes[i]) + ",");
            index++;
        }
        System.out.println("");
    }
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Use a ByteArrayInputStream and a DataInputStream to interpret
doubles in ByteBuffers or use allocate() instead of
allocateDirect() on Linux.
(Review ID: 179870) 
======================================================================