Search code examples
javaandroidstring-formattingfloating-accuracydouble-precision

Formatting Double to print without scientific notation using DecimalFormat


I have been reading timestamp values from sensor readings, but since they are provided in nanoseconds, I thought I would cast them to double and make the conversion. The resulting number is a 17 digit value, plus the separator.

Trying to print it directly results in scientific notation, which I don't want, so I use a DecimalFormat class to output it to an expected value of 4 decimal places. The problem is, even though the debugger shows a number of 17 decimal digits, even after the 'doubleValue()' call, the output string shows me a number of 15 digits.

Code:

...
Double timestamp = (new Date().getTime()) +       // Example: 1.3552299670232847E12
            ((event.timestamp - System.nanoTime()) / 1000000D);
DecimalFormat dfmt = new DecimalFormat("#.####");

switch(event.sensor.getType()){
    case Sensor.TYPE_LINEAR_ACCELERATION:
    case Sensor.TYPE_ACCELEROMETER:
        accel = event.values.clone();
        String line = "A" + LOGSEPARATOR +              
            dfmt.format(timestamp.doubleValue()) + // Prints: 1355229967023.28
...

I thought this might be an android precision problem, but the debugger has the formatter showing the wrong precision as well. I have tested this in a local java program and both calls have the same amount of digits.

Is this a DecimalFormat bug/limitation? Or am I doing something wrong?


Solution

  • There is indeed a difference between Java's and Android's DecimalFormat class, and they output different results, despite taking the exact same arguments.

    This was enough for me to try Henry's approach, and now that I have I see that I have gained an extra 2 places of precision. I am also confident that the values are calculated accurately, as only sums and multiplications are involved.

    This is the modified code I ended up using:

    ...
    long javaTime = new Date().getTime();
    long nanoTime = System.nanoTime();
    long newtimestamp = javaTime * 1000000 +            // Compute the timestamp
                (event.timestamp - nanoTime);           // in nanos first
    String longStr = Long.valueOf(newtimestamp).toString();
    String tsString = longStr.substring(0, longStr.length()-6) +// Format the output string
                "." + longStr.substring(longStr.length()-6);    // to have the comma in the
                                                                // correct space.
    ...