简体   繁体   中英

How to convert Java double to byte[], and byte[] to double (IEEE 754 double-precision binary floating-point format)

I have 3 methods (1 functional (double to byte[]), and one returning unexpected value (byte[] to double), and 1 method that is functional but performs to many operations to use Hex to double)).

Performance is the utmost importance, so if you have more efficient code, please share.

Functional method converts from double to byte[] getFloat64(11.27d) returns byte[]=hex string "40268A3D70A3D70A" :

public static byte[] getFloat64(double value)
    {
        final byte[] float64Bytes = new byte[8];
        long double64Long=Double.doubleToLongBits(value);
        float64Bytes[0] = (byte)((double64Long >> 56) & 0xff);
        float64Bytes[1] = (byte)((double64Long >> 48) & 0xff);        
        float64Bytes[2] = (byte)((double64Long >> 40) & 0xff);
        float64Bytes[3] = (byte)((double64Long >> 32) & 0xff);
        float64Bytes[4] = (byte)((double64Long >> 24) & 0xff);
        float64Bytes[5] = (byte)((double64Long >> 16) & 0xff);
        float64Bytes[6] = (byte)((double64Long >> 8) & 0xff);
        float64Bytes[7] = (byte)((double64Long >> 0) & 0xff);        
        return float64Bytes;
    }

Incorrect double value is returned from this byte[] to double method (calling getFloat64(getFloat64(11.27d)) returns 9.338087023E-315):

public static double getFloat64(byte[] bytes)
    {
        return Double.longBitsToDouble((long)((bytes[0] & 0xFF) << 56) 
            | ((bytes[1] & 0xFF) << 48) 
            | ((bytes[2] & 0xFF) << 40) 
            | ((bytes[3] & 0xFF) << 32)
            | ((bytes[4] & 0xFF) << 24) 
            | ((bytes[5] & 0xFF) << 16) 
            | ((bytes[6] & 0xFF) << 8) 
            | ((bytes[7] & 0xFF) << 0)); 
    }   

The final method returns the correct answer calling getFloat64("40268A3D70A3D70A") returns 11.27:

public double getFloat64(String hex_double)
    {
       long longBits = Long.valueOf(hex_double,16).longValue(); 
       return Double.longBitsToDouble(longBits);
    }

What is wrong with the middle method? Why does it not behave like the last method by returning 11.27?

The problem is that (bytes[0] & 0xFF) is still a 32-bit integer value. If you bit-shift it 56 bits to the left on a 32-bit value, Java shifts by 56 % 32 = 24 bits instead of 56 bits.

You first need to promote the value to 64-bit long before bit-shifting it. One way to do that is to & with a long value ( 0xFFL ). Any integral number-literal (that ordinarily has the type int and hence 32 bits) can be turned into a long-literal by appending L or l to it.

Corrected code:

public static double getFloat64(byte[] bytes)
    {
        return Double.longBitsToDouble(((bytes[0] & 0xFFL) << 56) 
            | ((bytes[1] & 0xFFL) << 48) 
            | ((bytes[2] & 0xFFL) << 40) 
            | ((bytes[3] & 0xFFL) << 32)
            | ((bytes[4] & 0xFFL) << 24) 
            | ((bytes[5] & 0xFFL) << 16) 
            | ((bytes[6] & 0xFFL) << 8) 
            | ((bytes[7] & 0xFFL) << 0)); 
    } 

ob-JLS reference: Java Language Specification 15.9 :

If the promoted type of the left-hand operand is int , only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM