Double to Hex String and Back

Why not use the methods provided in standard library: Double.valueOf and Double.toHexString

So a full round trip example would be

public static void main(String[] args){

    double doubleValue = -0.03454568;
    System.out.println("Initial double value is " + doubleValue);

    String hexStringRepresentation = Double.toHexString(doubleValue);
    System.out.println("Hex value is " + hexStringRepresentation);

    double roundtrippedDoubleValue = Double.valueOf(hexStringRepresentation);
    System.out.println("Round tripped double value is " + roundtrippedDoubleValue);
}

Nb Double.valueOf will give a boxed Double and Double.parseDouble will give a primitive double choose as appropriate.

or am I misunderstanding something?


You can break the String into two halves and parse each one, but I think this is the simplest.

long doubleAsLongReverse = new BigInteger(doubleAsString, 16).longValue();

In Java 8, there is now a

long l = Long.parseUnsignedLong(doubleAsString, 16);

and to reverse this

String s = Long.toUnsignedString(l, 16);

These can be used in combination with the methods converting raw double to long etc.


The problem is that the input value is negative, and the javadoc for Long.toHexString() states "Returns a string representation of the long argument as an unsigned integer in base 16. The unsigned long value is the argument plus 2^64 if the argument is negative; otherwise, it is equal to the argument." However parseLong states "Parses the string argument as a signed long in the radix..."

So when you have a negative input, that 2^64 causes the NumberFormatException.

If the input is changed to

double doubleInput = 9.156013e-002;

the conversion works correctly without an exception. To deal with a negative input, a little additional processing is needed.

Here is a class that shows one way to do the conversion without using BigInteger or byte buffers:

public class Temp {
  public String getDoubleAsHexString(double input) {
    // Convert the starting value to the equivalent value in a long
    long doubleAsLong = Double.doubleToRawLongBits(input);
    // and then convert the long to a hex string
    return Long.toHexString(doubleAsLong);
  }

  public double convertHexStrToDouble(String input) {
    // convert the input to positive, as needed
    String s2 = preprocess(input);
    boolean negative = true;
    // if the original equals the new string, then it is not negative
    if (input.equalsIgnoreCase(s2))
      negative = false;

    // convert the hex string to long
    long doubleAsLongReverse = Long.parseLong(s2, 16);

    // Convert the long back into the original double
    double doubleOutput = Double.longBitsToDouble(doubleAsLongReverse);

    // return as a negative value, as needed
    if (negative)
      return -doubleOutput;

    return doubleOutput;
  }

  private String preprocess(String doubleAsHexString) {
    // get the first char and convert it to an int
    String s0 = doubleAsHexString.substring(0, 1);
    int int1 = Integer.parseInt(s0, 16);

    // if the int is < 8, then the string is not negative
    // and is returned without further processing
    if (int1 < 8)
      return doubleAsHexString;

    // otherwise subtract 8
    int1 = int1 - 8;
    s0 = Integer.toString(int1);

    // don't prepend a "0"
    if (int1 == 0)
      s0 = "";

    // return the string with a new inital char
    return s0 + doubleAsHexString.substring(1);
  }
}

And here is a junit test class:

public class TempTest {
  private Temp t;

  @Before
  public void setUp() throws Exception {
    t = new Temp();
  }

  @Test
  public void testConvertHexStrToNegativeDouble() {
      double doubleInput = -9.156013e-002;
      String hexStr = t.getDoubleAsHexString(doubleInput);
      double doubleOutput = t.convertHexStrToDouble(hexStr);
      assertEquals(doubleInput, doubleOutput, 0.0);
    }

  @Test
  public void testConvertHexStrToPositiveDouble() {
    double doubleInput = 9.156013e-002;
    String hexStr = t.getDoubleAsHexString(doubleInput);
    double doubleOutput = t.convertHexStrToDouble(hexStr);
    assertEquals(doubleInput, doubleOutput, 0.0);
  }
}